shiva-code 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-OP4HYQZZ.js +163 -0
- package/dist/chunk-XVFDKDRZ.js +504 -0
- package/dist/client-2L7NWNCZ.js +8 -0
- package/dist/config-FGMZONWV.js +49 -0
- package/dist/index.js +961 -1060
- 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-XVFDKDRZ.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
|
}
|
|
@@ -7290,59 +6721,238 @@ var sessionsCommand = new Command13("sessions").description("Alle Claude Code Se
|
|
|
7290
6721
|
if (!projectExists) {
|
|
7291
6722
|
console.log(colors.dim(` Pfad existiert nicht mehr: ${project.absolutePath}`));
|
|
7292
6723
|
}
|
|
7293
|
-
if (project.sessions.length === 0) {
|
|
7294
|
-
log.dim(" Keine Sessions");
|
|
7295
|
-
log.newline();
|
|
7296
|
-
continue;
|
|
6724
|
+
if (project.sessions.length === 0) {
|
|
6725
|
+
log.dim(" Keine Sessions");
|
|
6726
|
+
log.newline();
|
|
6727
|
+
continue;
|
|
6728
|
+
}
|
|
6729
|
+
const displaySessions = project.sessions.slice(0, 5);
|
|
6730
|
+
for (let i = 0; i < displaySessions.length; i++) {
|
|
6731
|
+
const session = displaySessions[i];
|
|
6732
|
+
const num = String(i + 1).padStart(2, " ");
|
|
6733
|
+
let statusIcon = "";
|
|
6734
|
+
if (isSessionActive(session)) {
|
|
6735
|
+
statusIcon = colors.green(" [aktiv]");
|
|
6736
|
+
} else if (isSessionCorruptedQuick(session)) {
|
|
6737
|
+
statusIcon = colors.red(" [corrupted]");
|
|
6738
|
+
}
|
|
6739
|
+
const branch = session.gitBranch || "main";
|
|
6740
|
+
const msgs = `${session.messageCount} msgs`.padEnd(10);
|
|
6741
|
+
const time = formatRelativeTime(session.modified);
|
|
6742
|
+
let prompt = session.firstPrompt || "";
|
|
6743
|
+
if (prompt.length > 40) {
|
|
6744
|
+
prompt = prompt.substring(0, 37) + "...";
|
|
6745
|
+
}
|
|
6746
|
+
prompt = `"${prompt}"`;
|
|
6747
|
+
const tags = getSessionTags(session.sessionId);
|
|
6748
|
+
const tagsDisplay = tags.length > 0 ? " " + tags.map((t) => colors.magenta(`[${t}]`)).join(" ") : "";
|
|
6749
|
+
const line = [
|
|
6750
|
+
colors.dim(`${num}.`),
|
|
6751
|
+
branch.padEnd(15),
|
|
6752
|
+
colors.dim(`(${msgs})`),
|
|
6753
|
+
formatDate(session.modified).padEnd(14),
|
|
6754
|
+
colors.cyan(prompt),
|
|
6755
|
+
statusIcon,
|
|
6756
|
+
tagsDisplay
|
|
6757
|
+
].join(" ");
|
|
6758
|
+
console.log(` ${line}`);
|
|
6759
|
+
}
|
|
6760
|
+
if (project.sessions.length > 5) {
|
|
6761
|
+
log.dim(` ... und ${project.sessions.length - 5} weitere Sessions`);
|
|
6762
|
+
}
|
|
6763
|
+
log.newline();
|
|
6764
|
+
}
|
|
6765
|
+
const stats = await getSessionStats();
|
|
6766
|
+
log.dim(`Total: ${stats.activeProjects} Projekte, ${stats.totalSessions} Sessions`);
|
|
6767
|
+
log.newline();
|
|
6768
|
+
}));
|
|
6769
|
+
async function checkProjectExists(path15) {
|
|
6770
|
+
try {
|
|
6771
|
+
const fs15 = await import("fs");
|
|
6772
|
+
return fs15.existsSync(path15);
|
|
6773
|
+
} catch {
|
|
6774
|
+
return false;
|
|
6775
|
+
}
|
|
6776
|
+
}
|
|
6777
|
+
sessionsCommand.command("push").description("Sessions in Cloud sichern").option("-p, --project <pfad>", "Nur Sessions eines Projekts").action(async (options) => {
|
|
6778
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
6779
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
6780
|
+
const { getProjectConfig: getProjectConfig2 } = await import("./config-D6M6LI6U.js");
|
|
6781
|
+
if (!isAuthenticated2()) {
|
|
6782
|
+
log.error("Nicht angemeldet");
|
|
6783
|
+
log.info("Anmelden mit: shiva login");
|
|
6784
|
+
return;
|
|
6785
|
+
}
|
|
6786
|
+
let projects = await getAllClaudeProjects();
|
|
6787
|
+
if (options.project) {
|
|
6788
|
+
const found = await findProject(options.project);
|
|
6789
|
+
if (found) {
|
|
6790
|
+
projects = [found];
|
|
6791
|
+
} else {
|
|
6792
|
+
log.error(`Projekt nicht gefunden: ${options.project}`);
|
|
6793
|
+
return;
|
|
6794
|
+
}
|
|
6795
|
+
}
|
|
6796
|
+
projects = projects.filter((p) => p.sessions.length > 0);
|
|
6797
|
+
if (projects.length === 0) {
|
|
6798
|
+
log.warn("Keine Sessions zum Synchronisieren gefunden");
|
|
6799
|
+
return;
|
|
6800
|
+
}
|
|
6801
|
+
const spinner = ora9("Synchronisiere Sessions...").start();
|
|
6802
|
+
let syncedCount = 0;
|
|
6803
|
+
let errorCount = 0;
|
|
6804
|
+
for (const project of projects) {
|
|
6805
|
+
const config = getProjectConfig2(project.absolutePath);
|
|
6806
|
+
if (!config.projectId) {
|
|
6807
|
+
continue;
|
|
6808
|
+
}
|
|
6809
|
+
for (const session of project.sessions) {
|
|
6810
|
+
try {
|
|
6811
|
+
await api2.syncSession({
|
|
6812
|
+
sessionId: session.sessionId,
|
|
6813
|
+
projectId: config.projectId,
|
|
6814
|
+
summary: session.firstPrompt,
|
|
6815
|
+
messageCount: session.messageCount,
|
|
6816
|
+
firstPrompt: session.firstPrompt,
|
|
6817
|
+
gitBranch: session.gitBranch
|
|
6818
|
+
});
|
|
6819
|
+
syncedCount++;
|
|
6820
|
+
} catch {
|
|
6821
|
+
errorCount++;
|
|
6822
|
+
}
|
|
6823
|
+
}
|
|
6824
|
+
}
|
|
6825
|
+
spinner.stop();
|
|
6826
|
+
if (syncedCount > 0) {
|
|
6827
|
+
log.success(`${syncedCount} Sessions in Cloud gesichert`);
|
|
6828
|
+
}
|
|
6829
|
+
if (errorCount > 0) {
|
|
6830
|
+
log.warn(`${errorCount} Sessions konnten nicht gesichert werden`);
|
|
6831
|
+
}
|
|
6832
|
+
if (syncedCount === 0 && errorCount === 0) {
|
|
6833
|
+
log.info("Keine Projekte mit Cloud verbunden");
|
|
6834
|
+
log.dim("Verbinden mit: shiva init && shiva sync");
|
|
6835
|
+
}
|
|
6836
|
+
});
|
|
6837
|
+
sessionsCommand.command("pull").description("Sessions aus Cloud laden").option("--json", "JSON Output").action(async (options) => {
|
|
6838
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
6839
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
6840
|
+
if (!isAuthenticated2()) {
|
|
6841
|
+
log.error("Nicht angemeldet");
|
|
6842
|
+
log.info("Anmelden mit: shiva login");
|
|
6843
|
+
return;
|
|
6844
|
+
}
|
|
6845
|
+
const spinner = ora9("Lade Sessions aus Cloud...").start();
|
|
6846
|
+
try {
|
|
6847
|
+
const cloudSessions = await api2.getSessions();
|
|
6848
|
+
spinner.stop();
|
|
6849
|
+
if (options.json) {
|
|
6850
|
+
console.log(JSON.stringify(cloudSessions, null, 2));
|
|
6851
|
+
return;
|
|
6852
|
+
}
|
|
6853
|
+
if (cloudSessions.length === 0) {
|
|
6854
|
+
log.info("Keine Sessions in Cloud gefunden");
|
|
6855
|
+
log.dim("Hochladen mit: shiva sessions push");
|
|
6856
|
+
return;
|
|
6857
|
+
}
|
|
6858
|
+
log.success(`${cloudSessions.length} Sessions in Cloud gefunden`);
|
|
6859
|
+
log.newline();
|
|
6860
|
+
const byProject = /* @__PURE__ */ new Map();
|
|
6861
|
+
for (const session of cloudSessions) {
|
|
6862
|
+
const existing = byProject.get(session.projectId) || [];
|
|
6863
|
+
existing.push(session);
|
|
6864
|
+
byProject.set(session.projectId, existing);
|
|
7297
6865
|
}
|
|
7298
|
-
const
|
|
7299
|
-
|
|
7300
|
-
const session
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
} else if (isSessionCorruptedQuick(session)) {
|
|
7306
|
-
statusIcon = colors.red(" [corrupted]");
|
|
6866
|
+
for (const [projectId, sessions] of byProject.entries()) {
|
|
6867
|
+
console.log(colors.bold(`Projekt ID: ${projectId}`));
|
|
6868
|
+
for (const session of sessions.slice(0, 5)) {
|
|
6869
|
+
const data = session.data;
|
|
6870
|
+
const branch = data.gitBranch || "main";
|
|
6871
|
+
const msgs = data.messageCount || 0;
|
|
6872
|
+
log.dim(` ${session.sessionId.substring(0, 8)}... ${branch.padEnd(15)} ${msgs} msgs`);
|
|
7307
6873
|
}
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
const time = formatRelativeTime(session.modified);
|
|
7311
|
-
let prompt = session.firstPrompt || "";
|
|
7312
|
-
if (prompt.length > 40) {
|
|
7313
|
-
prompt = prompt.substring(0, 37) + "...";
|
|
6874
|
+
if (sessions.length > 5) {
|
|
6875
|
+
log.dim(` ... und ${sessions.length - 5} weitere`);
|
|
7314
6876
|
}
|
|
7315
|
-
|
|
7316
|
-
const tags = getSessionTags(session.sessionId);
|
|
7317
|
-
const tagsDisplay = tags.length > 0 ? " " + tags.map((t) => colors.magenta(`[${t}]`)).join(" ") : "";
|
|
7318
|
-
const line = [
|
|
7319
|
-
colors.dim(`${num}.`),
|
|
7320
|
-
branch.padEnd(15),
|
|
7321
|
-
colors.dim(`(${msgs})`),
|
|
7322
|
-
formatDate(session.modified).padEnd(14),
|
|
7323
|
-
colors.cyan(prompt),
|
|
7324
|
-
statusIcon,
|
|
7325
|
-
tagsDisplay
|
|
7326
|
-
].join(" ");
|
|
7327
|
-
console.log(` ${line}`);
|
|
6877
|
+
log.newline();
|
|
7328
6878
|
}
|
|
7329
|
-
|
|
7330
|
-
|
|
6879
|
+
} catch (error) {
|
|
6880
|
+
spinner.stop();
|
|
6881
|
+
log.error(error instanceof Error ? error.message : "Fehler beim Laden");
|
|
6882
|
+
}
|
|
6883
|
+
});
|
|
6884
|
+
sessionsCommand.command("sync").description("Sessions mit Cloud synchronisieren").option("-p, --project <pfad>", "Nur Sessions eines Projekts").action(async (options) => {
|
|
6885
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
6886
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
6887
|
+
const { getProjectConfig: getProjectConfig2 } = await import("./config-D6M6LI6U.js");
|
|
6888
|
+
if (!isAuthenticated2()) {
|
|
6889
|
+
log.error("Nicht angemeldet");
|
|
6890
|
+
log.info("Anmelden mit: shiva login");
|
|
6891
|
+
return;
|
|
6892
|
+
}
|
|
6893
|
+
let projects = await getAllClaudeProjects();
|
|
6894
|
+
if (options.project) {
|
|
6895
|
+
const found = await findProject(options.project);
|
|
6896
|
+
if (found) {
|
|
6897
|
+
projects = [found];
|
|
6898
|
+
} else {
|
|
6899
|
+
log.error(`Projekt nicht gefunden: ${options.project}`);
|
|
6900
|
+
return;
|
|
7331
6901
|
}
|
|
7332
|
-
log.newline();
|
|
7333
6902
|
}
|
|
7334
|
-
const
|
|
7335
|
-
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
6903
|
+
const spinner = ora9("Synchronisiere Sessions...").start();
|
|
6904
|
+
let pushedCount = 0;
|
|
6905
|
+
for (const project of projects.filter((p) => p.sessions.length > 0)) {
|
|
6906
|
+
const config = getProjectConfig2(project.absolutePath);
|
|
6907
|
+
if (!config.projectId) continue;
|
|
6908
|
+
for (const session of project.sessions) {
|
|
6909
|
+
try {
|
|
6910
|
+
await api2.syncSession({
|
|
6911
|
+
sessionId: session.sessionId,
|
|
6912
|
+
projectId: config.projectId,
|
|
6913
|
+
summary: session.firstPrompt,
|
|
6914
|
+
messageCount: session.messageCount,
|
|
6915
|
+
firstPrompt: session.firstPrompt,
|
|
6916
|
+
gitBranch: session.gitBranch
|
|
6917
|
+
});
|
|
6918
|
+
pushedCount++;
|
|
6919
|
+
} catch {
|
|
6920
|
+
}
|
|
6921
|
+
}
|
|
6922
|
+
}
|
|
6923
|
+
let cloudCount = 0;
|
|
7339
6924
|
try {
|
|
7340
|
-
const
|
|
7341
|
-
|
|
6925
|
+
const cloudSessions = await api2.getSessions();
|
|
6926
|
+
cloudCount = cloudSessions.length;
|
|
7342
6927
|
} catch {
|
|
7343
|
-
return false;
|
|
7344
6928
|
}
|
|
7345
|
-
|
|
6929
|
+
spinner.stop();
|
|
6930
|
+
log.success("Sessions synchronisiert");
|
|
6931
|
+
log.newline();
|
|
6932
|
+
log.tree.item(`${pushedCount} Sessions \u2192 Cloud`);
|
|
6933
|
+
log.tree.item(`${cloudCount} Sessions in Cloud`);
|
|
6934
|
+
log.newline();
|
|
6935
|
+
log.dim("Sessions werden automatisch mit lokalen Claude Sessions verkn\xFCpft");
|
|
6936
|
+
});
|
|
6937
|
+
sessionsCommand.command("delete <sessionId>").description("Session aus Cloud l\xF6schen").action(async (sessionId) => {
|
|
6938
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
6939
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
6940
|
+
if (!isAuthenticated2()) {
|
|
6941
|
+
log.error("Nicht angemeldet");
|
|
6942
|
+
log.info("Anmelden mit: shiva login");
|
|
6943
|
+
return;
|
|
6944
|
+
}
|
|
6945
|
+
try {
|
|
6946
|
+
const result = await api2.deleteSession(sessionId);
|
|
6947
|
+
if (result.success) {
|
|
6948
|
+
log.success("Session aus Cloud gel\xF6scht");
|
|
6949
|
+
} else {
|
|
6950
|
+
log.error(result.message || "Fehler beim L\xF6schen");
|
|
6951
|
+
}
|
|
6952
|
+
} catch (error) {
|
|
6953
|
+
log.error(error instanceof Error ? error.message : "Fehler beim L\xF6schen");
|
|
6954
|
+
}
|
|
6955
|
+
});
|
|
7346
6956
|
|
|
7347
6957
|
// src/commands/session/session.ts
|
|
7348
6958
|
import { Command as Command14 } from "commander";
|
|
@@ -7599,10 +7209,10 @@ sessionCommand.command("apply").description("Sandbox-\xC4nderungen \xFCbernehmen
|
|
|
7599
7209
|
log.header("Folgende \xC4nderungen werden \xFCbernommen:");
|
|
7600
7210
|
log.newline();
|
|
7601
7211
|
const pathsToApply = selectedPaths || diff.changes.map((c) => c.path);
|
|
7602
|
-
for (const
|
|
7603
|
-
const change = diff.changes.find((c) => c.path ===
|
|
7212
|
+
for (const path15 of pathsToApply) {
|
|
7213
|
+
const change = diff.changes.find((c) => c.path === path15);
|
|
7604
7214
|
if (change) {
|
|
7605
|
-
console.log(` ${formatChangeType(change.type)} ${
|
|
7215
|
+
console.log(` ${formatChangeType(change.type)} ${path15}`);
|
|
7606
7216
|
}
|
|
7607
7217
|
}
|
|
7608
7218
|
log.newline();
|
|
@@ -7759,18 +7369,18 @@ sessionCommand.command("config").description("Sandbox-Konfiguration verwalten").
|
|
|
7759
7369
|
log.success("Konfiguration zur\xFCckgesetzt");
|
|
7760
7370
|
return;
|
|
7761
7371
|
}
|
|
7762
|
-
const
|
|
7372
|
+
const config = sandboxService.getConfig();
|
|
7763
7373
|
if (options.show || Object.keys(options).length === 0) {
|
|
7764
7374
|
log.newline();
|
|
7765
7375
|
log.header("Sandbox Configuration");
|
|
7766
7376
|
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(
|
|
7377
|
+
log.keyValue("Enabled", config.enabled ? colors.green("Yes") : colors.red("No"));
|
|
7378
|
+
log.keyValue("Default Mode", config.defaultMode);
|
|
7379
|
+
log.keyValue("Auto Cleanup", config.autoCleanup ? "Yes" : "No");
|
|
7380
|
+
log.keyValue("Keep Days", String(config.keepDays));
|
|
7381
|
+
log.keyValue("Max Sandboxes", String(config.maxSandboxes));
|
|
7772
7382
|
log.newline();
|
|
7773
|
-
log.keyValue("Exclude Paths",
|
|
7383
|
+
log.keyValue("Exclude Paths", config.excludePaths.join(", "));
|
|
7774
7384
|
return;
|
|
7775
7385
|
}
|
|
7776
7386
|
const updates = {};
|
|
@@ -7797,7 +7407,7 @@ sessionCommand.command("config").description("Sandbox-Konfiguration verwalten").
|
|
|
7797
7407
|
import { Command as Command15 } from "commander";
|
|
7798
7408
|
import { spawn as spawn5, spawnSync as spawnSync5 } from "child_process";
|
|
7799
7409
|
import * as fs5 from "fs";
|
|
7800
|
-
import * as
|
|
7410
|
+
import * as path5 from "path";
|
|
7801
7411
|
import inquirer6 from "inquirer";
|
|
7802
7412
|
var githubCommand = new Command15("github").description("GitHub Integration verwalten").action(() => {
|
|
7803
7413
|
showStatus();
|
|
@@ -7861,9 +7471,9 @@ function showStatus() {
|
|
|
7861
7471
|
console.log(colors.dim("SHIVA Integration:"));
|
|
7862
7472
|
if (hasShivaDir(cwd)) {
|
|
7863
7473
|
log.success(".shiva/ Ordner existiert");
|
|
7864
|
-
const
|
|
7865
|
-
log.keyValue(" Context Injection",
|
|
7866
|
-
log.keyValue(" Branch Sessions", String(Object.keys(
|
|
7474
|
+
const config = getProjectConfig(cwd);
|
|
7475
|
+
log.keyValue(" Context Injection", config.autoInjectContext ? "aktiviert" : "deaktiviert");
|
|
7476
|
+
log.keyValue(" Branch Sessions", String(Object.keys(config.branchSessions).length));
|
|
7867
7477
|
} else {
|
|
7868
7478
|
log.warn(".shiva/ nicht initialisiert");
|
|
7869
7479
|
log.info("Initialisieren mit: shiva github init");
|
|
@@ -7902,9 +7512,9 @@ function initProject(projectPath, skipGitignore) {
|
|
|
7902
7512
|
}
|
|
7903
7513
|
if (hasShivaDir(projectPath)) {
|
|
7904
7514
|
log.warn(".shiva/ existiert bereits");
|
|
7905
|
-
const
|
|
7906
|
-
log.keyValue("Version", String(
|
|
7907
|
-
log.keyValue("Branch Sessions", String(Object.keys(
|
|
7515
|
+
const config = getProjectConfig(projectPath);
|
|
7516
|
+
log.keyValue("Version", String(config.version));
|
|
7517
|
+
log.keyValue("Branch Sessions", String(Object.keys(config.branchSessions).length));
|
|
7908
7518
|
log.newline();
|
|
7909
7519
|
log.info('Nutze "shiva github status" f\xFCr Details');
|
|
7910
7520
|
return;
|
|
@@ -8219,9 +7829,9 @@ githubCommand.command("git-hook").description("Git Hooks f\xFCr Branch-Session I
|
|
|
8219
7829
|
log.error("Kein Git Repository");
|
|
8220
7830
|
return;
|
|
8221
7831
|
}
|
|
8222
|
-
const gitDir =
|
|
8223
|
-
const hooksDir =
|
|
8224
|
-
const hookFile =
|
|
7832
|
+
const gitDir = path5.join(cwd, ".git");
|
|
7833
|
+
const hooksDir = path5.join(gitDir, "hooks");
|
|
7834
|
+
const hookFile = path5.join(hooksDir, "post-checkout");
|
|
8225
7835
|
if (options.uninstall) {
|
|
8226
7836
|
if (fs5.existsSync(hookFile)) {
|
|
8227
7837
|
const content = fs5.readFileSync(hookFile, "utf-8");
|
|
@@ -8610,10 +8220,10 @@ var prsCommand = new Command17("prs").description("GitHub Pull Requests \xFCber
|
|
|
8610
8220
|
import { Command as Command18 } from "commander";
|
|
8611
8221
|
import { readFile } from "fs/promises";
|
|
8612
8222
|
import { existsSync as existsSync12 } from "fs";
|
|
8613
|
-
import { join as
|
|
8223
|
+
import { join as join6, resolve as resolve7 } from "path";
|
|
8614
8224
|
|
|
8615
8225
|
// src/services/security/package-scanner.ts
|
|
8616
|
-
import
|
|
8226
|
+
import Conf3 from "conf";
|
|
8617
8227
|
|
|
8618
8228
|
// src/types/package.ts
|
|
8619
8229
|
var DEFAULT_PACKAGE_SCAN_CONFIG = {
|
|
@@ -8900,7 +8510,7 @@ var KNOWN_MALICIOUS_PACKAGES = [
|
|
|
8900
8510
|
// src/services/security/package-scanner.ts
|
|
8901
8511
|
var CACHE_TTL = 60 * 60 * 1e3;
|
|
8902
8512
|
var packageInfoCache = /* @__PURE__ */ new Map();
|
|
8903
|
-
var configStore = new
|
|
8513
|
+
var configStore = new Conf3({
|
|
8904
8514
|
projectName: "shiva-code",
|
|
8905
8515
|
defaults: {
|
|
8906
8516
|
packageSecurity: DEFAULT_PACKAGE_SCAN_CONFIG
|
|
@@ -9171,8 +8781,8 @@ var PackageScannerService = class {
|
|
|
9171
8781
|
* Check download count
|
|
9172
8782
|
*/
|
|
9173
8783
|
checkDownloadCount(weeklyDownloads, manager) {
|
|
9174
|
-
const
|
|
9175
|
-
const minDownloads =
|
|
8784
|
+
const config = this.getConfig();
|
|
8785
|
+
const minDownloads = config.minDownloads;
|
|
9176
8786
|
if (weeklyDownloads < 10) {
|
|
9177
8787
|
return {
|
|
9178
8788
|
name: "Downloads",
|
|
@@ -9208,7 +8818,7 @@ var PackageScannerService = class {
|
|
|
9208
8818
|
* Check package age
|
|
9209
8819
|
*/
|
|
9210
8820
|
checkPublishAge(publishedAt) {
|
|
9211
|
-
const
|
|
8821
|
+
const config = this.getConfig();
|
|
9212
8822
|
const publishDate = new Date(publishedAt);
|
|
9213
8823
|
const now = /* @__PURE__ */ new Date();
|
|
9214
8824
|
const ageInDays = Math.floor((now.getTime() - publishDate.getTime()) / (1e3 * 60 * 60 * 24));
|
|
@@ -9220,11 +8830,11 @@ var PackageScannerService = class {
|
|
|
9220
8830
|
severity: "critical"
|
|
9221
8831
|
};
|
|
9222
8832
|
}
|
|
9223
|
-
if (ageInDays <
|
|
8833
|
+
if (ageInDays < config.maxAgeDays) {
|
|
9224
8834
|
return {
|
|
9225
8835
|
name: "Age",
|
|
9226
8836
|
status: "fail",
|
|
9227
|
-
message: `${ageInDays} days old (< ${
|
|
8837
|
+
message: `${ageInDays} days old (< ${config.maxAgeDays} days)`,
|
|
9228
8838
|
severity: "high"
|
|
9229
8839
|
};
|
|
9230
8840
|
}
|
|
@@ -9257,8 +8867,8 @@ var PackageScannerService = class {
|
|
|
9257
8867
|
* Check for typosquatting
|
|
9258
8868
|
*/
|
|
9259
8869
|
checkTyposquatting(name, manager) {
|
|
9260
|
-
const
|
|
9261
|
-
if (!
|
|
8870
|
+
const config = this.getConfig();
|
|
8871
|
+
if (!config.checkTyposquatting) {
|
|
9262
8872
|
return {
|
|
9263
8873
|
name: "Typosquatting",
|
|
9264
8874
|
status: "pass",
|
|
@@ -9286,8 +8896,8 @@ var PackageScannerService = class {
|
|
|
9286
8896
|
* Check install scripts for suspicious patterns
|
|
9287
8897
|
*/
|
|
9288
8898
|
checkScripts(scripts) {
|
|
9289
|
-
const
|
|
9290
|
-
if (!
|
|
8899
|
+
const config = this.getConfig();
|
|
8900
|
+
if (!config.checkScripts || !scripts) {
|
|
9291
8901
|
return {
|
|
9292
8902
|
name: "Scripts",
|
|
9293
8903
|
status: "pass",
|
|
@@ -9388,8 +8998,8 @@ var PackageScannerService = class {
|
|
|
9388
8998
|
* Check blocklist
|
|
9389
8999
|
*/
|
|
9390
9000
|
checkBlocklist(name, manager) {
|
|
9391
|
-
const
|
|
9392
|
-
const blocked =
|
|
9001
|
+
const config = this.getConfig();
|
|
9002
|
+
const blocked = config.blocklist.find((entry) => entry.package === name && entry.manager === manager);
|
|
9393
9003
|
if (blocked) {
|
|
9394
9004
|
return {
|
|
9395
9005
|
name: "Blocklist",
|
|
@@ -9420,8 +9030,8 @@ var PackageScannerService = class {
|
|
|
9420
9030
|
* Check allowlist
|
|
9421
9031
|
*/
|
|
9422
9032
|
isAllowlisted(name) {
|
|
9423
|
-
const
|
|
9424
|
-
return
|
|
9033
|
+
const config = this.getConfig();
|
|
9034
|
+
return config.allowlist.includes(name);
|
|
9425
9035
|
}
|
|
9426
9036
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
9427
9037
|
// Typosquatting Detection
|
|
@@ -9733,7 +9343,7 @@ var PackageScannerService = class {
|
|
|
9733
9343
|
* Generate hook output for Claude Code
|
|
9734
9344
|
*/
|
|
9735
9345
|
generateHookOutput(results) {
|
|
9736
|
-
const
|
|
9346
|
+
const config = this.getConfig();
|
|
9737
9347
|
const blockedPackages = results.filter((r) => r.recommendation === "block");
|
|
9738
9348
|
const warnPackages = results.filter((r) => r.recommendation === "warn");
|
|
9739
9349
|
if (blockedPackages.length > 0) {
|
|
@@ -9750,7 +9360,7 @@ var PackageScannerService = class {
|
|
|
9750
9360
|
|
|
9751
9361
|
Did you mean: ${pkg.suggestion}?`;
|
|
9752
9362
|
}
|
|
9753
|
-
if (
|
|
9363
|
+
if (config.autoBlock) {
|
|
9754
9364
|
return {
|
|
9755
9365
|
decision: "block",
|
|
9756
9366
|
reason
|
|
@@ -9790,64 +9400,64 @@ Continue with caution.`
|
|
|
9790
9400
|
* Add a package to the blocklist
|
|
9791
9401
|
*/
|
|
9792
9402
|
addToBlocklist(entry) {
|
|
9793
|
-
const
|
|
9794
|
-
const existing =
|
|
9403
|
+
const config = this.getConfig();
|
|
9404
|
+
const existing = config.blocklist.find(
|
|
9795
9405
|
(e) => e.package === entry.package && e.manager === entry.manager
|
|
9796
9406
|
);
|
|
9797
9407
|
if (existing) {
|
|
9798
9408
|
existing.reason = entry.reason;
|
|
9799
9409
|
existing.source = entry.source;
|
|
9800
9410
|
} else {
|
|
9801
|
-
|
|
9411
|
+
config.blocklist.push({
|
|
9802
9412
|
...entry,
|
|
9803
9413
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9804
9414
|
});
|
|
9805
9415
|
}
|
|
9806
|
-
this.updateConfig(
|
|
9416
|
+
this.updateConfig(config);
|
|
9807
9417
|
}
|
|
9808
9418
|
/**
|
|
9809
9419
|
* Remove a package from the blocklist
|
|
9810
9420
|
*/
|
|
9811
9421
|
removeFromBlocklist(packageName, manager) {
|
|
9812
|
-
const
|
|
9813
|
-
const index =
|
|
9422
|
+
const config = this.getConfig();
|
|
9423
|
+
const index = config.blocklist.findIndex(
|
|
9814
9424
|
(e) => e.package === packageName && e.manager === manager
|
|
9815
9425
|
);
|
|
9816
9426
|
if (index === -1) {
|
|
9817
9427
|
return false;
|
|
9818
9428
|
}
|
|
9819
|
-
|
|
9820
|
-
this.updateConfig(
|
|
9429
|
+
config.blocklist.splice(index, 1);
|
|
9430
|
+
this.updateConfig(config);
|
|
9821
9431
|
return true;
|
|
9822
9432
|
}
|
|
9823
9433
|
/**
|
|
9824
9434
|
* Check if a package is blocked
|
|
9825
9435
|
*/
|
|
9826
9436
|
isBlocked(name, manager) {
|
|
9827
|
-
const
|
|
9828
|
-
return
|
|
9437
|
+
const config = this.getConfig();
|
|
9438
|
+
return config.blocklist.some((e) => e.package === name && e.manager === manager) || KNOWN_MALICIOUS_PACKAGES.some((e) => e.package === name && e.manager === manager);
|
|
9829
9439
|
}
|
|
9830
9440
|
/**
|
|
9831
9441
|
* Add a package to the allowlist
|
|
9832
9442
|
*/
|
|
9833
9443
|
addToAllowlist(packageName) {
|
|
9834
|
-
const
|
|
9835
|
-
if (!
|
|
9836
|
-
|
|
9837
|
-
this.updateConfig(
|
|
9444
|
+
const config = this.getConfig();
|
|
9445
|
+
if (!config.allowlist.includes(packageName)) {
|
|
9446
|
+
config.allowlist.push(packageName);
|
|
9447
|
+
this.updateConfig(config);
|
|
9838
9448
|
}
|
|
9839
9449
|
}
|
|
9840
9450
|
/**
|
|
9841
9451
|
* Remove a package from the allowlist
|
|
9842
9452
|
*/
|
|
9843
9453
|
removeFromAllowlist(packageName) {
|
|
9844
|
-
const
|
|
9845
|
-
const index =
|
|
9454
|
+
const config = this.getConfig();
|
|
9455
|
+
const index = config.allowlist.indexOf(packageName);
|
|
9846
9456
|
if (index === -1) {
|
|
9847
9457
|
return false;
|
|
9848
9458
|
}
|
|
9849
|
-
|
|
9850
|
-
this.updateConfig(
|
|
9459
|
+
config.allowlist.splice(index, 1);
|
|
9460
|
+
this.updateConfig(config);
|
|
9851
9461
|
return true;
|
|
9852
9462
|
}
|
|
9853
9463
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -9862,9 +9472,9 @@ Continue with caution.`
|
|
|
9862
9472
|
/**
|
|
9863
9473
|
* Update configuration
|
|
9864
9474
|
*/
|
|
9865
|
-
updateConfig(
|
|
9475
|
+
updateConfig(config) {
|
|
9866
9476
|
const current = this.getConfig();
|
|
9867
|
-
configStore.set("packageSecurity", { ...current, ...
|
|
9477
|
+
configStore.set("packageSecurity", { ...current, ...config });
|
|
9868
9478
|
}
|
|
9869
9479
|
/**
|
|
9870
9480
|
* Reset configuration to defaults
|
|
@@ -9963,9 +9573,9 @@ async function parsePackageJson(filePath) {
|
|
|
9963
9573
|
}
|
|
9964
9574
|
const dir = resolve7(filePath, "..");
|
|
9965
9575
|
let manager = "npm";
|
|
9966
|
-
if (existsSync12(
|
|
9576
|
+
if (existsSync12(join6(dir, "pnpm-lock.yaml"))) {
|
|
9967
9577
|
manager = "pnpm";
|
|
9968
|
-
} else if (existsSync12(
|
|
9578
|
+
} else if (existsSync12(join6(dir, "yarn.lock"))) {
|
|
9969
9579
|
manager = "yarn";
|
|
9970
9580
|
}
|
|
9971
9581
|
return { packages, manager };
|
|
@@ -10006,22 +9616,22 @@ async function parseCargoToml(filePath) {
|
|
|
10006
9616
|
}
|
|
10007
9617
|
return packages;
|
|
10008
9618
|
}
|
|
10009
|
-
function displayConfig(
|
|
9619
|
+
function displayConfig(config) {
|
|
10010
9620
|
log.header("Package Security Config");
|
|
10011
9621
|
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",
|
|
9622
|
+
log.keyValue("Enabled", config.enabled ? colors.green("Yes") : colors.red("No"));
|
|
9623
|
+
log.keyValue("Auto-block", config.autoBlock ? colors.red("Yes") : colors.green("No"));
|
|
9624
|
+
log.keyValue("Min downloads", `${config.minDownloads}/week`);
|
|
9625
|
+
log.keyValue("Max age", `${config.maxAgeDays} days`);
|
|
9626
|
+
log.keyValue("Typosquatting check", config.checkTyposquatting ? "Yes" : "No");
|
|
9627
|
+
log.keyValue("Script check", config.checkScripts ? "Yes" : "No");
|
|
10018
9628
|
log.newline();
|
|
10019
|
-
log.keyValue("Blocklist entries", `${
|
|
10020
|
-
log.keyValue("Allowlist entries", `${
|
|
9629
|
+
log.keyValue("Blocklist entries", `${config.blocklist.length}`);
|
|
9630
|
+
log.keyValue("Allowlist entries", `${config.allowlist.length}`);
|
|
10021
9631
|
}
|
|
10022
9632
|
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 (!
|
|
9633
|
+
const config = packageScanner.getConfig();
|
|
9634
|
+
if (!config.enabled && !options.hookMode) {
|
|
10025
9635
|
log.warn("Package scanning is disabled. Enable it with: shiva scan config --enable");
|
|
10026
9636
|
return;
|
|
10027
9637
|
}
|
|
@@ -10066,15 +9676,15 @@ var scanCommand = new Command18("scan").description("Scanne Packages auf Sicherh
|
|
|
10066
9676
|
}
|
|
10067
9677
|
if (options.project) {
|
|
10068
9678
|
const cwd = process.cwd();
|
|
10069
|
-
if (existsSync12(
|
|
10070
|
-
const parsed = await parsePackageJson(
|
|
9679
|
+
if (existsSync12(join6(cwd, "package.json"))) {
|
|
9680
|
+
const parsed = await parsePackageJson(join6(cwd, "package.json"));
|
|
10071
9681
|
packagesToScan = parsed.packages;
|
|
10072
9682
|
manager = parsed.manager;
|
|
10073
|
-
} else if (existsSync12(
|
|
10074
|
-
packagesToScan = await parseRequirementsTxt(
|
|
9683
|
+
} else if (existsSync12(join6(cwd, "requirements.txt"))) {
|
|
9684
|
+
packagesToScan = await parseRequirementsTxt(join6(cwd, "requirements.txt"));
|
|
10075
9685
|
manager = "pip";
|
|
10076
|
-
} else if (existsSync12(
|
|
10077
|
-
packagesToScan = await parseCargoToml(
|
|
9686
|
+
} else if (existsSync12(join6(cwd, "Cargo.toml"))) {
|
|
9687
|
+
packagesToScan = await parseCargoToml(join6(cwd, "Cargo.toml"));
|
|
10078
9688
|
manager = "cargo";
|
|
10079
9689
|
} else {
|
|
10080
9690
|
log.error("No dependency file found in current directory");
|
|
@@ -10138,14 +9748,14 @@ var blocklistCommand = new Command18("blocklist").description("Verwalte Package-
|
|
|
10138
9748
|
}
|
|
10139
9749
|
return;
|
|
10140
9750
|
}
|
|
10141
|
-
const
|
|
10142
|
-
if (
|
|
9751
|
+
const config = packageScanner.getConfig();
|
|
9752
|
+
if (config.blocklist.length === 0) {
|
|
10143
9753
|
log.info("Blocklist is empty");
|
|
10144
9754
|
return;
|
|
10145
9755
|
}
|
|
10146
9756
|
log.header("Blocked Packages");
|
|
10147
9757
|
log.newline();
|
|
10148
|
-
for (const entry of
|
|
9758
|
+
for (const entry of config.blocklist) {
|
|
10149
9759
|
log.plain(`${colors.red("\u2717")} ${entry.package} (${entry.manager})`);
|
|
10150
9760
|
log.plain(colors.dim(` Reason: ${entry.reason}`));
|
|
10151
9761
|
log.plain(colors.dim(` Added: ${entry.addedAt} (${entry.source})`));
|
|
@@ -10166,14 +9776,14 @@ var allowlistCommand = new Command18("allowlist").description("Verwalte Package-
|
|
|
10166
9776
|
}
|
|
10167
9777
|
return;
|
|
10168
9778
|
}
|
|
10169
|
-
const
|
|
10170
|
-
if (
|
|
9779
|
+
const config = packageScanner.getConfig();
|
|
9780
|
+
if (config.allowlist.length === 0) {
|
|
10171
9781
|
log.info("Allowlist is empty");
|
|
10172
9782
|
return;
|
|
10173
9783
|
}
|
|
10174
9784
|
log.header("Allowed Packages");
|
|
10175
9785
|
log.newline();
|
|
10176
|
-
for (const pkg of
|
|
9786
|
+
for (const pkg of config.allowlist) {
|
|
10177
9787
|
log.plain(`${colors.green("\u2713")} ${pkg}`);
|
|
10178
9788
|
}
|
|
10179
9789
|
});
|
|
@@ -10230,9 +9840,9 @@ var permissionsCommand = new Command19("permissions").description("Permission-By
|
|
|
10230
9840
|
if (!hasShivaDir(projectPath)) {
|
|
10231
9841
|
initShivaDir(projectPath);
|
|
10232
9842
|
}
|
|
10233
|
-
const
|
|
9843
|
+
const config = getSecurityConfig(projectPath);
|
|
10234
9844
|
if (options.status || Object.keys(options).filter((k) => k !== "noSkip").length === 0) {
|
|
10235
|
-
displayPermissionsStatus(
|
|
9845
|
+
displayPermissionsStatus(config.permissions);
|
|
10236
9846
|
return;
|
|
10237
9847
|
}
|
|
10238
9848
|
if (options.skip) {
|
|
@@ -10248,7 +9858,7 @@ var permissionsCommand = new Command19("permissions").description("Permission-By
|
|
|
10248
9858
|
log.success("Permissions werden von global geerbt");
|
|
10249
9859
|
}
|
|
10250
9860
|
if (options.blockTool) {
|
|
10251
|
-
const current =
|
|
9861
|
+
const current = config.permissions.blockedTools;
|
|
10252
9862
|
if (!current.includes(options.blockTool)) {
|
|
10253
9863
|
updatePermissions(projectPath, { blockedTools: [...current, options.blockTool] });
|
|
10254
9864
|
log.success(`Tool blockiert: ${options.blockTool}`);
|
|
@@ -10257,21 +9867,21 @@ var permissionsCommand = new Command19("permissions").description("Permission-By
|
|
|
10257
9867
|
}
|
|
10258
9868
|
}
|
|
10259
9869
|
if (options.unblockTool) {
|
|
10260
|
-
const current =
|
|
9870
|
+
const current = config.permissions.blockedTools;
|
|
10261
9871
|
updatePermissions(projectPath, {
|
|
10262
9872
|
blockedTools: current.filter((t) => t !== options.unblockTool)
|
|
10263
9873
|
});
|
|
10264
9874
|
log.success(`Tool-Block aufgehoben: ${options.unblockTool}`);
|
|
10265
9875
|
}
|
|
10266
9876
|
if (options.allowPath) {
|
|
10267
|
-
const current =
|
|
9877
|
+
const current = config.permissions.allowedPaths;
|
|
10268
9878
|
if (!current.includes(options.allowPath)) {
|
|
10269
9879
|
updatePermissions(projectPath, { allowedPaths: [...current, options.allowPath] });
|
|
10270
9880
|
log.success(`Pfad erlaubt: ${options.allowPath}`);
|
|
10271
9881
|
}
|
|
10272
9882
|
}
|
|
10273
9883
|
if (options.blockPath) {
|
|
10274
|
-
const current =
|
|
9884
|
+
const current = config.permissions.blockedPaths;
|
|
10275
9885
|
if (!current.includes(options.blockPath)) {
|
|
10276
9886
|
updatePermissions(projectPath, { blockedPaths: [...current, options.blockPath] });
|
|
10277
9887
|
log.success(`Pfad blockiert: ${options.blockPath}`);
|
|
@@ -10279,7 +9889,7 @@ var permissionsCommand = new Command19("permissions").description("Permission-By
|
|
|
10279
9889
|
}
|
|
10280
9890
|
displayPermissionsStatus(getSecurityConfig(projectPath).permissions);
|
|
10281
9891
|
});
|
|
10282
|
-
function displayPermissionsStatus(
|
|
9892
|
+
function displayPermissionsStatus(config) {
|
|
10283
9893
|
log.newline();
|
|
10284
9894
|
console.log(colors.orange.bold("Permission-Einstellungen"));
|
|
10285
9895
|
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 +9899,11 @@ function displayPermissionsStatus(config2) {
|
|
|
10289
9899
|
"no-skip": colors.green("Aktiv (Permission-Prompts)"),
|
|
10290
9900
|
"inherit": colors.dim("(erbt von global)")
|
|
10291
9901
|
};
|
|
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",
|
|
9902
|
+
log.keyValue("Modus", modeDisplay[config.skipPermissions]);
|
|
9903
|
+
log.keyValue("Erlaubte Tools", config.allowedTools === "all" ? "Alle" : config.allowedTools.join(", ") || "Keine");
|
|
9904
|
+
log.keyValue("Blockierte Tools", config.blockedTools.length > 0 ? config.blockedTools.join(", ") : colors.dim("Keine"));
|
|
9905
|
+
log.keyValue("Erlaubte Pfade", config.allowedPaths.length > 0 ? config.allowedPaths.join(", ") : colors.dim("Alle"));
|
|
9906
|
+
log.keyValue("Blockierte Pfade", config.blockedPaths.length > 0 ? config.blockedPaths.join(", ") : colors.dim("Keine"));
|
|
10297
9907
|
log.newline();
|
|
10298
9908
|
}
|
|
10299
9909
|
securityCommand.addCommand(permissionsCommand);
|
|
@@ -10302,9 +9912,9 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10302
9912
|
if (!hasShivaDir(projectPath)) {
|
|
10303
9913
|
initShivaDir(projectPath);
|
|
10304
9914
|
}
|
|
10305
|
-
const
|
|
9915
|
+
const config = getSecurityConfig(projectPath);
|
|
10306
9916
|
if (options.status || !strategy && Object.keys(options).length === 0) {
|
|
10307
|
-
displayApprovalStatus(
|
|
9917
|
+
displayApprovalStatus(config.approval);
|
|
10308
9918
|
return;
|
|
10309
9919
|
}
|
|
10310
9920
|
if (strategy) {
|
|
@@ -10323,7 +9933,7 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10323
9933
|
log.error("Ung\xFCltige Zahl");
|
|
10324
9934
|
return;
|
|
10325
9935
|
}
|
|
10326
|
-
updateApproval(projectPath, { thresholds: { ...
|
|
9936
|
+
updateApproval(projectPath, { thresholds: { ...config.approval.thresholds, autoApproveMaxFiles: n } });
|
|
10327
9937
|
log.success(`Max. Dateien f\xFCr Auto-Approval: ${n}`);
|
|
10328
9938
|
}
|
|
10329
9939
|
if (options.maxLines) {
|
|
@@ -10332,15 +9942,15 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10332
9942
|
log.error("Ung\xFCltige Zahl");
|
|
10333
9943
|
return;
|
|
10334
9944
|
}
|
|
10335
|
-
updateApproval(projectPath, { thresholds: { ...
|
|
9945
|
+
updateApproval(projectPath, { thresholds: { ...config.approval.thresholds, autoApproveMaxLines: n } });
|
|
10336
9946
|
log.success(`Max. Zeilen f\xFCr Auto-Approval: ${n}`);
|
|
10337
9947
|
}
|
|
10338
9948
|
if (options.require) {
|
|
10339
|
-
const current =
|
|
9949
|
+
const current = config.approval.thresholds.requireApprovalPatterns;
|
|
10340
9950
|
if (!current.includes(options.require)) {
|
|
10341
9951
|
updateApproval(projectPath, {
|
|
10342
9952
|
thresholds: {
|
|
10343
|
-
...
|
|
9953
|
+
...config.approval.thresholds,
|
|
10344
9954
|
requireApprovalPatterns: [...current, options.require]
|
|
10345
9955
|
}
|
|
10346
9956
|
});
|
|
@@ -10348,11 +9958,11 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10348
9958
|
}
|
|
10349
9959
|
}
|
|
10350
9960
|
if (options.skip) {
|
|
10351
|
-
const current =
|
|
9961
|
+
const current = config.approval.thresholds.skipApprovalPatterns;
|
|
10352
9962
|
if (!current.includes(options.skip)) {
|
|
10353
9963
|
updateApproval(projectPath, {
|
|
10354
9964
|
thresholds: {
|
|
10355
|
-
...
|
|
9965
|
+
...config.approval.thresholds,
|
|
10356
9966
|
skipApprovalPatterns: [...current, options.skip]
|
|
10357
9967
|
}
|
|
10358
9968
|
});
|
|
@@ -10360,20 +9970,20 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10360
9970
|
}
|
|
10361
9971
|
}
|
|
10362
9972
|
if (options.removeRequire) {
|
|
10363
|
-
const current =
|
|
9973
|
+
const current = config.approval.thresholds.requireApprovalPatterns;
|
|
10364
9974
|
updateApproval(projectPath, {
|
|
10365
9975
|
thresholds: {
|
|
10366
|
-
...
|
|
9976
|
+
...config.approval.thresholds,
|
|
10367
9977
|
requireApprovalPatterns: current.filter((p) => p !== options.removeRequire)
|
|
10368
9978
|
}
|
|
10369
9979
|
});
|
|
10370
9980
|
log.success(`Require-Pattern entfernt: ${options.removeRequire}`);
|
|
10371
9981
|
}
|
|
10372
9982
|
if (options.removeSkip) {
|
|
10373
|
-
const current =
|
|
9983
|
+
const current = config.approval.thresholds.skipApprovalPatterns;
|
|
10374
9984
|
updateApproval(projectPath, {
|
|
10375
9985
|
thresholds: {
|
|
10376
|
-
...
|
|
9986
|
+
...config.approval.thresholds,
|
|
10377
9987
|
skipApprovalPatterns: current.filter((p) => p !== options.removeSkip)
|
|
10378
9988
|
}
|
|
10379
9989
|
});
|
|
@@ -10381,7 +9991,7 @@ var approvalCommand = new Command19("approval").description("Plan-Approval-Strat
|
|
|
10381
9991
|
}
|
|
10382
9992
|
displayApprovalStatus(getSecurityConfig(projectPath).approval);
|
|
10383
9993
|
});
|
|
10384
|
-
function displayApprovalStatus(
|
|
9994
|
+
function displayApprovalStatus(config) {
|
|
10385
9995
|
log.newline();
|
|
10386
9996
|
console.log(colors.orange.bold("Approval-Einstellungen"));
|
|
10387
9997
|
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 +10001,12 @@ function displayApprovalStatus(config2) {
|
|
|
10391
10001
|
"manual": colors.green("Manuell"),
|
|
10392
10002
|
"hybrid": colors.cyan("Hybrid")
|
|
10393
10003
|
};
|
|
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",
|
|
10004
|
+
log.keyValue("Strategie", strategyDisplay[config.strategy]);
|
|
10005
|
+
if (config.strategy === "hybrid") {
|
|
10006
|
+
log.keyValue("Max. Dateien", String(config.thresholds.autoApproveMaxFiles));
|
|
10007
|
+
log.keyValue("Max. Zeilen", String(config.thresholds.autoApproveMaxLines));
|
|
10008
|
+
log.keyValue("Require-Patterns", config.thresholds.requireApprovalPatterns.join(", ") || colors.dim("Keine"));
|
|
10009
|
+
log.keyValue("Skip-Patterns", config.thresholds.skipApprovalPatterns.join(", ") || colors.dim("Keine"));
|
|
10400
10010
|
}
|
|
10401
10011
|
log.newline();
|
|
10402
10012
|
}
|
|
@@ -10430,16 +10040,16 @@ securityCommand.command("set-tier <tier>").description("Security-Tier setzen (be
|
|
|
10430
10040
|
log.newline();
|
|
10431
10041
|
displayTierInfo(tier, preset);
|
|
10432
10042
|
});
|
|
10433
|
-
function displayTierInfo(tier,
|
|
10043
|
+
function displayTierInfo(tier, config) {
|
|
10434
10044
|
console.log(colors.orange.bold(`Tier: ${tier}`));
|
|
10435
10045
|
console.log(colors.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
10436
10046
|
log.newline();
|
|
10437
10047
|
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: ${
|
|
10048
|
+
log.plain(` ${check(config.skipPermissions)} Skip Permissions`);
|
|
10049
|
+
log.plain(` ${check(config.dockerIsolation)} Docker Isolation`);
|
|
10050
|
+
log.plain(` ${check(config.require2FA)} 2FA erforderlich`);
|
|
10051
|
+
log.plain(` ${check(config.timeRestrictions)} Zeit-Einschr\xE4nkungen`);
|
|
10052
|
+
log.plain(` Approval: ${config.approvalStrategy}`);
|
|
10443
10053
|
log.newline();
|
|
10444
10054
|
}
|
|
10445
10055
|
securityCommand.command("audit").description("Sicherheits-Audit durchf\xFChren").action(async () => {
|
|
@@ -10449,15 +10059,15 @@ securityCommand.command("audit").description("Sicherheits-Audit durchf\xFChren")
|
|
|
10449
10059
|
log.info("Initialisiere mit: shiva project time --enable");
|
|
10450
10060
|
return;
|
|
10451
10061
|
}
|
|
10452
|
-
const
|
|
10453
|
-
const audit = performSecurityAudit(
|
|
10062
|
+
const config = getProjectConfigV2(projectPath);
|
|
10063
|
+
const audit = performSecurityAudit(config);
|
|
10454
10064
|
displaySecurityAudit(audit);
|
|
10455
10065
|
});
|
|
10456
|
-
function performSecurityAudit(
|
|
10066
|
+
function performSecurityAudit(config) {
|
|
10457
10067
|
const checks = [];
|
|
10458
10068
|
const recommendations = [];
|
|
10459
10069
|
let score = 10;
|
|
10460
|
-
if (
|
|
10070
|
+
if (config.security.permissions.skipPermissions === "skip") {
|
|
10461
10071
|
checks.push({
|
|
10462
10072
|
name: "Permissions",
|
|
10463
10073
|
status: "warn",
|
|
@@ -10465,7 +10075,7 @@ function performSecurityAudit(config2) {
|
|
|
10465
10075
|
});
|
|
10466
10076
|
recommendations.push("Deaktiviere Skip-Permissions f\xFCr erh\xF6hte Sicherheit");
|
|
10467
10077
|
score -= 2;
|
|
10468
|
-
} else if (
|
|
10078
|
+
} else if (config.security.permissions.skipPermissions === "no-skip") {
|
|
10469
10079
|
checks.push({
|
|
10470
10080
|
name: "Permissions",
|
|
10471
10081
|
status: "pass",
|
|
@@ -10478,11 +10088,11 @@ function performSecurityAudit(config2) {
|
|
|
10478
10088
|
message: "Erbt von global"
|
|
10479
10089
|
});
|
|
10480
10090
|
}
|
|
10481
|
-
if (
|
|
10091
|
+
if (config.security.permissions.blockedPaths.length > 0) {
|
|
10482
10092
|
checks.push({
|
|
10483
10093
|
name: "Pfad-Blocking",
|
|
10484
10094
|
status: "pass",
|
|
10485
|
-
message: `${
|
|
10095
|
+
message: `${config.security.permissions.blockedPaths.length} Pfade blockiert`
|
|
10486
10096
|
});
|
|
10487
10097
|
} else {
|
|
10488
10098
|
checks.push({
|
|
@@ -10493,13 +10103,13 @@ function performSecurityAudit(config2) {
|
|
|
10493
10103
|
recommendations.push("Blockiere sensible Pfade wie .env oder secrets/");
|
|
10494
10104
|
score -= 1;
|
|
10495
10105
|
}
|
|
10496
|
-
if (
|
|
10106
|
+
if (config.security.approval.strategy === "manual") {
|
|
10497
10107
|
checks.push({
|
|
10498
10108
|
name: "Approval",
|
|
10499
10109
|
status: "pass",
|
|
10500
10110
|
message: "Manuelle Genehmigung"
|
|
10501
10111
|
});
|
|
10502
|
-
} else if (
|
|
10112
|
+
} else if (config.security.approval.strategy === "hybrid") {
|
|
10503
10113
|
checks.push({
|
|
10504
10114
|
name: "Approval",
|
|
10505
10115
|
status: "pass",
|
|
@@ -10514,7 +10124,7 @@ function performSecurityAudit(config2) {
|
|
|
10514
10124
|
recommendations.push("Wechsle zu hybrid oder manual Approval");
|
|
10515
10125
|
score -= 1;
|
|
10516
10126
|
}
|
|
10517
|
-
if (
|
|
10127
|
+
if (config.docker.enabled === true) {
|
|
10518
10128
|
checks.push({
|
|
10519
10129
|
name: "Docker",
|
|
10520
10130
|
status: "pass",
|
|
@@ -10529,24 +10139,24 @@ function performSecurityAudit(config2) {
|
|
|
10529
10139
|
recommendations.push("Aktiviere Docker f\xFCr isolierte Ausf\xFChrung");
|
|
10530
10140
|
score -= 1;
|
|
10531
10141
|
}
|
|
10532
|
-
if (
|
|
10142
|
+
if (config.docker.enabled && config.docker.network === "none") {
|
|
10533
10143
|
checks.push({
|
|
10534
10144
|
name: "Netzwerk",
|
|
10535
10145
|
status: "pass",
|
|
10536
10146
|
message: "Netzwerk-Isolation aktiv"
|
|
10537
10147
|
});
|
|
10538
|
-
} else if (
|
|
10148
|
+
} else if (config.docker.enabled && config.docker.network === "bridge") {
|
|
10539
10149
|
checks.push({
|
|
10540
10150
|
name: "Netzwerk",
|
|
10541
10151
|
status: "warn",
|
|
10542
10152
|
message: "Bridge-Netzwerk"
|
|
10543
10153
|
});
|
|
10544
10154
|
}
|
|
10545
|
-
if (
|
|
10155
|
+
if (config.session.timeControl.enabled) {
|
|
10546
10156
|
checks.push({
|
|
10547
10157
|
name: "Zeitkontrolle",
|
|
10548
10158
|
status: "pass",
|
|
10549
|
-
message: `${
|
|
10159
|
+
message: `${config.session.timeControl.allowedHours.start}-${config.session.timeControl.allowedHours.end}`
|
|
10550
10160
|
});
|
|
10551
10161
|
} else {
|
|
10552
10162
|
checks.push({
|
|
@@ -10556,7 +10166,7 @@ function performSecurityAudit(config2) {
|
|
|
10556
10166
|
});
|
|
10557
10167
|
score -= 0.5;
|
|
10558
10168
|
}
|
|
10559
|
-
const hasBudget =
|
|
10169
|
+
const hasBudget = config.session.budget.dailyTokenLimit || config.session.budget.weeklyTokenLimit || config.session.budget.monthlyTokenLimit;
|
|
10560
10170
|
if (hasBudget) {
|
|
10561
10171
|
checks.push({
|
|
10562
10172
|
name: "Token-Budget",
|
|
@@ -10571,7 +10181,7 @@ function performSecurityAudit(config2) {
|
|
|
10571
10181
|
});
|
|
10572
10182
|
score -= 0.5;
|
|
10573
10183
|
}
|
|
10574
|
-
if (
|
|
10184
|
+
if (config.security.require2FA) {
|
|
10575
10185
|
checks.push({
|
|
10576
10186
|
name: "2FA",
|
|
10577
10187
|
status: "pass",
|
|
@@ -10587,7 +10197,7 @@ function performSecurityAudit(config2) {
|
|
|
10587
10197
|
score -= 1;
|
|
10588
10198
|
}
|
|
10589
10199
|
return {
|
|
10590
|
-
tier:
|
|
10200
|
+
tier: config.security.tier,
|
|
10591
10201
|
checks,
|
|
10592
10202
|
recommendations,
|
|
10593
10203
|
score: Math.max(0, Math.round(score))
|
|
@@ -10623,23 +10233,23 @@ securityCommand.command("status").description("Sicherheitsstatus anzeigen").acti
|
|
|
10623
10233
|
log.info("Initialisiere mit: shiva project time --enable");
|
|
10624
10234
|
return;
|
|
10625
10235
|
}
|
|
10626
|
-
const
|
|
10236
|
+
const config = getProjectConfigV2(projectPath);
|
|
10627
10237
|
log.newline();
|
|
10628
10238
|
console.log(colors.orange.bold("SHIVA Security Status"));
|
|
10629
10239
|
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
10240
|
log.newline();
|
|
10631
|
-
log.keyValue("Security-Tier",
|
|
10632
|
-
log.keyValue("2FA erforderlich",
|
|
10241
|
+
log.keyValue("Security-Tier", config.security.tier);
|
|
10242
|
+
log.keyValue("2FA erforderlich", config.security.require2FA ? "Ja" : "Nein");
|
|
10633
10243
|
log.newline();
|
|
10634
|
-
displayPermissionsStatus(
|
|
10635
|
-
displayApprovalStatus(
|
|
10244
|
+
displayPermissionsStatus(config.security.permissions);
|
|
10245
|
+
displayApprovalStatus(config.security.approval);
|
|
10636
10246
|
});
|
|
10637
10247
|
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
10248
|
if (!isAuthenticated()) {
|
|
10639
10249
|
log.error("Nicht angemeldet. Verwende: shiva login");
|
|
10640
10250
|
return;
|
|
10641
10251
|
}
|
|
10642
|
-
const
|
|
10252
|
+
const config = getConfig();
|
|
10643
10253
|
if (options.status || Object.keys(options).length === 0) {
|
|
10644
10254
|
try {
|
|
10645
10255
|
const status = await twoFactorService.getStatus();
|
|
@@ -10661,7 +10271,7 @@ var tfaCommand = new Command19("2fa").description("Zwei-Faktor-Authentifizierung
|
|
|
10661
10271
|
if (options.enable) {
|
|
10662
10272
|
try {
|
|
10663
10273
|
log.info("Initialisiere 2FA-Setup...");
|
|
10664
|
-
const setup = await twoFactorService.startSetup(
|
|
10274
|
+
const setup = await twoFactorService.startSetup(config.email || "");
|
|
10665
10275
|
displayQRCode(setup.qrCodeDataUrl);
|
|
10666
10276
|
log.plain(`Oder manuell eingeben: ${colors.cyan(setup.secret)}`);
|
|
10667
10277
|
log.newline();
|
|
@@ -10778,7 +10388,7 @@ import { Command as Command20 } from "commander";
|
|
|
10778
10388
|
import inquirer8 from "inquirer";
|
|
10779
10389
|
import ora13 from "ora";
|
|
10780
10390
|
import * as fs6 from "fs";
|
|
10781
|
-
import * as
|
|
10391
|
+
import * as path6 from "path";
|
|
10782
10392
|
|
|
10783
10393
|
// src/utils/clipboard.ts
|
|
10784
10394
|
import { execSync as execSync2, spawnSync as spawnSync6 } from "child_process";
|
|
@@ -11103,7 +10713,7 @@ secretsCommand.command("import").description(".env Datei in Vault importieren").
|
|
|
11103
10713
|
log.errorWithSuggestion(Errors.NOT_AUTHENTICATED());
|
|
11104
10714
|
return;
|
|
11105
10715
|
}
|
|
11106
|
-
const filePath =
|
|
10716
|
+
const filePath = path6.resolve(file);
|
|
11107
10717
|
if (!fs6.existsSync(filePath)) {
|
|
11108
10718
|
log.errorWithSuggestion(Errors.FILE_NOT_FOUND(file));
|
|
11109
10719
|
return;
|
|
@@ -11136,7 +10746,7 @@ secretsCommand.command("import").description(".env Datei in Vault importieren").
|
|
|
11136
10746
|
log.listItem(`${secret.key} = ${preview}`);
|
|
11137
10747
|
}
|
|
11138
10748
|
log.newline();
|
|
11139
|
-
log.dim(`${secrets.length} Secret(s) aus ${
|
|
10749
|
+
log.dim(`${secrets.length} Secret(s) aus ${path6.basename(file)}`);
|
|
11140
10750
|
log.newline();
|
|
11141
10751
|
if (options.dryRun) {
|
|
11142
10752
|
log.info("Dry-run: Keine \xC4nderungen vorgenommen");
|
|
@@ -11233,22 +10843,22 @@ import ora14 from "ora";
|
|
|
11233
10843
|
|
|
11234
10844
|
// src/services/data/memory.ts
|
|
11235
10845
|
import * as fs7 from "fs";
|
|
11236
|
-
import * as
|
|
11237
|
-
import * as
|
|
10846
|
+
import * as path7 from "path";
|
|
10847
|
+
import * as os4 from "os";
|
|
11238
10848
|
function findAllClaudeMdFiles() {
|
|
11239
10849
|
const results = [];
|
|
11240
|
-
const sessionsPath =
|
|
10850
|
+
const sessionsPath = path7.join(os4.homedir(), ".claude", "projects");
|
|
11241
10851
|
if (fs7.existsSync(sessionsPath)) {
|
|
11242
10852
|
const dirs = fs7.readdirSync(sessionsPath);
|
|
11243
10853
|
for (const dir of dirs) {
|
|
11244
10854
|
const projectPath = decodeProjectPath(dir);
|
|
11245
10855
|
if (projectPath && fs7.existsSync(projectPath)) {
|
|
11246
|
-
const claudeMdPath =
|
|
10856
|
+
const claudeMdPath = path7.join(projectPath, "CLAUDE.md");
|
|
11247
10857
|
if (fs7.existsSync(claudeMdPath)) {
|
|
11248
10858
|
results.push({
|
|
11249
10859
|
path: claudeMdPath,
|
|
11250
10860
|
projectPath,
|
|
11251
|
-
projectName:
|
|
10861
|
+
projectName: path7.basename(projectPath)
|
|
11252
10862
|
});
|
|
11253
10863
|
}
|
|
11254
10864
|
}
|
|
@@ -11326,7 +10936,6 @@ async function getAllMemories() {
|
|
|
11326
10936
|
return Array.from(memoryMap.values());
|
|
11327
10937
|
}
|
|
11328
10938
|
async function searchMemories(query, options = {}) {
|
|
11329
|
-
const allMemories = await getAllMemories();
|
|
11330
10939
|
const {
|
|
11331
10940
|
caseSensitive = false,
|
|
11332
10941
|
category,
|
|
@@ -11335,24 +10944,57 @@ async function searchMemories(query, options = {}) {
|
|
|
11335
10944
|
limit = 100
|
|
11336
10945
|
} = options;
|
|
11337
10946
|
const searchQuery = caseSensitive ? query : query.toLowerCase();
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
10947
|
+
let allMemories = [];
|
|
10948
|
+
if (source === "local" || source === "all") {
|
|
10949
|
+
const localMemories = getLocalMemories();
|
|
10950
|
+
allMemories.push(...localMemories);
|
|
10951
|
+
}
|
|
10952
|
+
if ((source === "cloud" || source === "all") && isAuthenticated()) {
|
|
10953
|
+
try {
|
|
10954
|
+
const cloudResults = await api.searchMemories(query);
|
|
10955
|
+
const cloudMemories = cloudResults.map((m) => ({
|
|
10956
|
+
key: m.key,
|
|
10957
|
+
value: m.value,
|
|
10958
|
+
category: m.category,
|
|
10959
|
+
source: "cloud",
|
|
10960
|
+
projectName: m.projectName,
|
|
10961
|
+
projectPath: "",
|
|
10962
|
+
// Not returned by search API
|
|
10963
|
+
projectId: m.projectId,
|
|
10964
|
+
memoryId: m.id
|
|
10965
|
+
}));
|
|
10966
|
+
allMemories.push(...cloudMemories);
|
|
10967
|
+
} catch {
|
|
10968
|
+
const cloudMemories = await getCloudMemories();
|
|
10969
|
+
allMemories.push(...cloudMemories);
|
|
10970
|
+
}
|
|
10971
|
+
}
|
|
10972
|
+
const memoryMap = /* @__PURE__ */ new Map();
|
|
10973
|
+
for (const memory of allMemories) {
|
|
10974
|
+
const key = `${memory.projectName}:${memory.key}`;
|
|
10975
|
+
if (!memoryMap.has(key) || memory.source === "cloud") {
|
|
10976
|
+
memoryMap.set(key, memory);
|
|
11341
10977
|
}
|
|
10978
|
+
}
|
|
10979
|
+
allMemories = Array.from(memoryMap.values());
|
|
10980
|
+
const filtered = allMemories.filter((memory) => {
|
|
11342
10981
|
if (category && memory.category !== category) {
|
|
11343
10982
|
return false;
|
|
11344
10983
|
}
|
|
11345
10984
|
if (project) {
|
|
11346
|
-
const projectMatch = caseSensitive ? memory.projectName.includes(project)
|
|
10985
|
+
const projectMatch = caseSensitive ? memory.projectName.includes(project) : memory.projectName.toLowerCase().includes(project.toLowerCase());
|
|
11347
10986
|
if (!projectMatch) {
|
|
11348
10987
|
return false;
|
|
11349
10988
|
}
|
|
11350
10989
|
}
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
10990
|
+
if (memory.source === "local") {
|
|
10991
|
+
const searchFields = [memory.key, memory.value, memory.category];
|
|
10992
|
+
const haystack = caseSensitive ? searchFields.join(" ") : searchFields.join(" ").toLowerCase();
|
|
10993
|
+
return haystack.includes(searchQuery);
|
|
10994
|
+
}
|
|
10995
|
+
return true;
|
|
11354
10996
|
});
|
|
11355
|
-
const projectSet = new Set(filtered.map((m) => m.
|
|
10997
|
+
const projectSet = new Set(filtered.map((m) => m.projectName));
|
|
11356
10998
|
return {
|
|
11357
10999
|
memories: filtered.slice(0, limit),
|
|
11358
11000
|
totalCount: filtered.length,
|
|
@@ -11360,7 +11002,7 @@ async function searchMemories(query, options = {}) {
|
|
|
11360
11002
|
};
|
|
11361
11003
|
}
|
|
11362
11004
|
function deleteLocalMemory(projectPath, key) {
|
|
11363
|
-
const claudeMdPath =
|
|
11005
|
+
const claudeMdPath = path7.join(projectPath, "CLAUDE.md");
|
|
11364
11006
|
if (!fs7.existsSync(claudeMdPath)) {
|
|
11365
11007
|
return false;
|
|
11366
11008
|
}
|
|
@@ -11410,7 +11052,7 @@ async function deleteMemory(projectPath, key, options = {}) {
|
|
|
11410
11052
|
}
|
|
11411
11053
|
async function deleteAllProjectMemories(projectPath) {
|
|
11412
11054
|
const result = { local: 0, cloud: 0 };
|
|
11413
|
-
const claudeMdPath =
|
|
11055
|
+
const claudeMdPath = path7.join(projectPath, "CLAUDE.md");
|
|
11414
11056
|
if (fs7.existsSync(claudeMdPath)) {
|
|
11415
11057
|
try {
|
|
11416
11058
|
let content = fs7.readFileSync(claudeMdPath, "utf-8");
|
|
@@ -11439,8 +11081,8 @@ async function deleteAllProjectMemories(projectPath) {
|
|
|
11439
11081
|
return result;
|
|
11440
11082
|
}
|
|
11441
11083
|
async function getContextPreview(projectPath) {
|
|
11442
|
-
const projectName =
|
|
11443
|
-
const claudeMdPath =
|
|
11084
|
+
const projectName = path7.basename(projectPath);
|
|
11085
|
+
const claudeMdPath = path7.join(projectPath, "CLAUDE.md");
|
|
11444
11086
|
const preview = {
|
|
11445
11087
|
projectName,
|
|
11446
11088
|
projectPath,
|
|
@@ -11462,8 +11104,8 @@ async function getContextPreview(projectPath) {
|
|
|
11462
11104
|
projectPath
|
|
11463
11105
|
}));
|
|
11464
11106
|
}
|
|
11465
|
-
const shivaDir =
|
|
11466
|
-
const contextPath =
|
|
11107
|
+
const shivaDir = path7.join(projectPath, ".shiva");
|
|
11108
|
+
const contextPath = path7.join(shivaDir, "github-context.md");
|
|
11467
11109
|
if (fs7.existsSync(contextPath)) {
|
|
11468
11110
|
const content = fs7.readFileSync(contextPath, "utf-8");
|
|
11469
11111
|
preview.githubContext = content;
|
|
@@ -11557,7 +11199,7 @@ function escapeRegex2(str) {
|
|
|
11557
11199
|
|
|
11558
11200
|
// src/commands/memory/forget.ts
|
|
11559
11201
|
import { Command as Command22 } from "commander";
|
|
11560
|
-
import * as
|
|
11202
|
+
import * as path8 from "path";
|
|
11561
11203
|
import inquirer9 from "inquirer";
|
|
11562
11204
|
import ora15 from "ora";
|
|
11563
11205
|
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 +11207,7 @@ var forgetCommand = new Command22("forget").description("Memories l\xF6schen (GD
|
|
|
11565
11207
|
console.log(colors.orange.bold("SHIVA Code - Forget"));
|
|
11566
11208
|
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
11209
|
log.newline();
|
|
11568
|
-
const projectPath = options.project ?
|
|
11210
|
+
const projectPath = options.project ? path8.resolve(options.project) : process.cwd();
|
|
11569
11211
|
if (options.all) {
|
|
11570
11212
|
await handleDeleteAll(projectPath, options);
|
|
11571
11213
|
return;
|
|
@@ -11581,7 +11223,7 @@ var forgetCommand = new Command22("forget").description("Memories l\xF6schen (GD
|
|
|
11581
11223
|
await handleInteractiveDelete(projectPath, options);
|
|
11582
11224
|
});
|
|
11583
11225
|
async function handleDeleteAll(projectPath, options) {
|
|
11584
|
-
const projectName =
|
|
11226
|
+
const projectName = path8.basename(projectPath);
|
|
11585
11227
|
console.log(colors.red.bold("\u26A0\uFE0F WARNUNG: Alle Memories l\xF6schen"));
|
|
11586
11228
|
console.log(colors.dim(`Projekt: ${projectName}`));
|
|
11587
11229
|
console.log(colors.dim(`Pfad: ${projectPath}`));
|
|
@@ -11687,7 +11329,7 @@ async function handleDeleteBySearch(query, projectPath, options) {
|
|
|
11687
11329
|
}
|
|
11688
11330
|
async function handleDeleteKey(key, projectPath, options) {
|
|
11689
11331
|
console.log(colors.bold(`Memory l\xF6schen: ${key}`));
|
|
11690
|
-
console.log(colors.dim(`Projekt: ${
|
|
11332
|
+
console.log(colors.dim(`Projekt: ${path8.basename(projectPath)}`));
|
|
11691
11333
|
log.newline();
|
|
11692
11334
|
if (options.dryRun) {
|
|
11693
11335
|
log.info("Dry-run: Keine \xC4nderungen werden vorgenommen");
|
|
@@ -11802,12 +11444,12 @@ function truncate(str, maxLen) {
|
|
|
11802
11444
|
|
|
11803
11445
|
// src/commands/memory/context.ts
|
|
11804
11446
|
import { Command as Command23 } from "commander";
|
|
11805
|
-
import * as
|
|
11447
|
+
import * as path9 from "path";
|
|
11806
11448
|
import * as fs8 from "fs";
|
|
11807
11449
|
import ora16 from "ora";
|
|
11808
11450
|
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 =
|
|
11451
|
+
const projectPath = options.dir ? path9.resolve(options.dir) : process.cwd();
|
|
11452
|
+
const projectName = path9.basename(projectPath);
|
|
11811
11453
|
if (!fs8.existsSync(projectPath)) {
|
|
11812
11454
|
log.error(`Verzeichnis nicht gefunden: ${projectPath}`);
|
|
11813
11455
|
return;
|
|
@@ -12191,14 +11833,14 @@ async function resolveSessionId(input) {
|
|
|
12191
11833
|
|
|
12192
11834
|
// src/commands/memory/export.ts
|
|
12193
11835
|
import { Command as Command25 } from "commander";
|
|
12194
|
-
import * as
|
|
11836
|
+
import * as path11 from "path";
|
|
12195
11837
|
import * as fs10 from "fs";
|
|
12196
11838
|
import ora17 from "ora";
|
|
12197
11839
|
import inquirer11 from "inquirer";
|
|
12198
11840
|
|
|
12199
11841
|
// src/services/session/export.ts
|
|
12200
11842
|
import * as fs9 from "fs";
|
|
12201
|
-
import * as
|
|
11843
|
+
import * as path10 from "path";
|
|
12202
11844
|
import { execSync as execSync3 } from "child_process";
|
|
12203
11845
|
async function exportSession(sessionId, options = {}) {
|
|
12204
11846
|
const projects = await getAllClaudeProjects();
|
|
@@ -12214,7 +11856,7 @@ async function exportSession(sessionId, options = {}) {
|
|
|
12214
11856
|
tags: getSessionTags(sessionId)
|
|
12215
11857
|
};
|
|
12216
11858
|
if (options.includeTranscript) {
|
|
12217
|
-
const transcriptPath =
|
|
11859
|
+
const transcriptPath = path10.join(
|
|
12218
11860
|
getClaudeProjectsPath(),
|
|
12219
11861
|
encodeProjectPath(project.absolutePath),
|
|
12220
11862
|
session.sessionId + ".jsonl"
|
|
@@ -12224,7 +11866,7 @@ async function exportSession(sessionId, options = {}) {
|
|
|
12224
11866
|
}
|
|
12225
11867
|
}
|
|
12226
11868
|
if (options.includeConversation && options.includeTranscript) {
|
|
12227
|
-
const transcriptPath =
|
|
11869
|
+
const transcriptPath = path10.join(
|
|
12228
11870
|
getClaudeProjectsPath(),
|
|
12229
11871
|
encodeProjectPath(project.absolutePath),
|
|
12230
11872
|
session.sessionId + ".jsonl"
|
|
@@ -12265,7 +11907,7 @@ async function exportSessions(sessionIds, outputDir, options = {}) {
|
|
|
12265
11907
|
const exported = await exportSession(sessionId, options);
|
|
12266
11908
|
if (exported) {
|
|
12267
11909
|
const filename = `${exported.projectName}-${sessionId.slice(0, 8)}.json`;
|
|
12268
|
-
const filepath =
|
|
11910
|
+
const filepath = path10.join(outputDir, filename);
|
|
12269
11911
|
fs9.writeFileSync(filepath, JSON.stringify(exported, null, 2));
|
|
12270
11912
|
success++;
|
|
12271
11913
|
} else {
|
|
@@ -12295,7 +11937,7 @@ function createBackupArchive(outputPath, projectPaths) {
|
|
|
12295
11937
|
if (projectPaths && projectPaths.length > 0) {
|
|
12296
11938
|
for (const p of projectPaths) {
|
|
12297
11939
|
const encoded = encodeProjectPath(p);
|
|
12298
|
-
const fullPath =
|
|
11940
|
+
const fullPath = path10.join(claudeDir, encoded);
|
|
12299
11941
|
if (fs9.existsSync(fullPath)) {
|
|
12300
11942
|
includePaths.push(encoded);
|
|
12301
11943
|
}
|
|
@@ -12303,7 +11945,7 @@ function createBackupArchive(outputPath, projectPaths) {
|
|
|
12303
11945
|
} else {
|
|
12304
11946
|
const entries = fs9.readdirSync(claudeDir);
|
|
12305
11947
|
includePaths = entries.filter((e) => {
|
|
12306
|
-
const stat = fs9.statSync(
|
|
11948
|
+
const stat = fs9.statSync(path10.join(claudeDir, e));
|
|
12307
11949
|
return stat.isDirectory();
|
|
12308
11950
|
});
|
|
12309
11951
|
}
|
|
@@ -12323,11 +11965,11 @@ async function importSession(data, targetProjectPath) {
|
|
|
12323
11965
|
try {
|
|
12324
11966
|
const projectPath = targetProjectPath || data.projectPath;
|
|
12325
11967
|
const encodedPath = encodeProjectPath(projectPath);
|
|
12326
|
-
const sessionDir =
|
|
11968
|
+
const sessionDir = path10.join(getClaudeProjectsPath(), encodedPath);
|
|
12327
11969
|
if (!fs9.existsSync(sessionDir)) {
|
|
12328
11970
|
fs9.mkdirSync(sessionDir, { recursive: true });
|
|
12329
11971
|
}
|
|
12330
|
-
const sessionFile =
|
|
11972
|
+
const sessionFile = path10.join(sessionDir, data.session.sessionId + ".jsonl");
|
|
12331
11973
|
if (fs9.existsSync(sessionFile)) {
|
|
12332
11974
|
return {
|
|
12333
11975
|
success: false,
|
|
@@ -12399,7 +12041,7 @@ async function importSessionsFromDirectory(dirPath, targetProjectPath) {
|
|
|
12399
12041
|
let success = 0;
|
|
12400
12042
|
let failed = 0;
|
|
12401
12043
|
for (const file of files) {
|
|
12402
|
-
const filepath =
|
|
12044
|
+
const filepath = path10.join(dirPath, file);
|
|
12403
12045
|
const result = await importSessionFromFile(filepath, targetProjectPath);
|
|
12404
12046
|
results.push(result);
|
|
12405
12047
|
if (result.success) {
|
|
@@ -12477,7 +12119,7 @@ var importCommand = new Command25("import").description("Sessions importieren").
|
|
|
12477
12119
|
console.log(colors.orange.bold("SHIVA Code - Import"));
|
|
12478
12120
|
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
12121
|
log.newline();
|
|
12480
|
-
const absolutePath =
|
|
12122
|
+
const absolutePath = path11.resolve(inputPath);
|
|
12481
12123
|
if (!fs10.existsSync(absolutePath)) {
|
|
12482
12124
|
log.error(`Datei nicht gefunden: ${absolutePath}`);
|
|
12483
12125
|
return;
|
|
@@ -12500,7 +12142,7 @@ var importCommand = new Command25("import").description("Sessions importieren").
|
|
|
12500
12142
|
async function handleBackup(outputPath) {
|
|
12501
12143
|
const spinner = ora17("Erstelle Backup...").start();
|
|
12502
12144
|
const filename = `shiva-backup-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.tar.gz`;
|
|
12503
|
-
const output = outputPath ||
|
|
12145
|
+
const output = outputPath || path11.join(process.cwd(), filename);
|
|
12504
12146
|
const success = createBackupArchive(output);
|
|
12505
12147
|
if (success) {
|
|
12506
12148
|
spinner.succeed(`Backup erstellt: ${output}`);
|
|
@@ -12519,7 +12161,7 @@ async function handleExportAll(outputDir, options = {}) {
|
|
|
12519
12161
|
return;
|
|
12520
12162
|
}
|
|
12521
12163
|
spinner.text = `Exportiere ${allSessionIds.length} Sessions...`;
|
|
12522
|
-
const output = outputDir ||
|
|
12164
|
+
const output = outputDir || path11.join(process.cwd(), "shiva-export");
|
|
12523
12165
|
const result = await exportSessions(allSessionIds, output, options);
|
|
12524
12166
|
spinner.succeed(`Export abgeschlossen`);
|
|
12525
12167
|
log.info(`${result.success} Sessions exportiert`);
|
|
@@ -12543,7 +12185,7 @@ async function handleExportProject(projectName, outputDir, options = {}) {
|
|
|
12543
12185
|
return;
|
|
12544
12186
|
}
|
|
12545
12187
|
spinner.text = `Exportiere ${project.sessions.length} Sessions aus ${project.projectName}...`;
|
|
12546
|
-
const output = outputDir ||
|
|
12188
|
+
const output = outputDir || path11.join(process.cwd(), `${project.projectName}-export`);
|
|
12547
12189
|
const result = await exportProjectSessions(project.absolutePath, output, options);
|
|
12548
12190
|
spinner.succeed(`Export abgeschlossen`);
|
|
12549
12191
|
log.info(`${result.success} Sessions exportiert`);
|
|
@@ -12672,15 +12314,15 @@ var rememberCommand = new Command26("remember").description("Memory in der Cloud
|
|
|
12672
12314
|
return;
|
|
12673
12315
|
}
|
|
12674
12316
|
const projectPath = process.cwd();
|
|
12675
|
-
const
|
|
12676
|
-
if (!
|
|
12317
|
+
const config = getProjectConfig(projectPath);
|
|
12318
|
+
if (!config.projectId) {
|
|
12677
12319
|
log.error("Projekt nicht mit Cloud verbunden");
|
|
12678
12320
|
log.info("Verbinden mit: shiva init && shiva sync");
|
|
12679
12321
|
return;
|
|
12680
12322
|
}
|
|
12681
12323
|
const key = options.key || text.substring(0, 50).replace(/[^a-zA-Z0-9]/g, "_");
|
|
12682
12324
|
try {
|
|
12683
|
-
const result = await api.addMemory(
|
|
12325
|
+
const result = await api.addMemory(config.projectId, {
|
|
12684
12326
|
key,
|
|
12685
12327
|
value: text,
|
|
12686
12328
|
category: options.category
|
|
@@ -12700,8 +12342,8 @@ var rememberCommand = new Command26("remember").description("Memory in der Cloud
|
|
|
12700
12342
|
import { Command as Command27 } from "commander";
|
|
12701
12343
|
import { execSync as execSync4 } from "child_process";
|
|
12702
12344
|
import * as fs11 from "fs";
|
|
12703
|
-
import * as
|
|
12704
|
-
import * as
|
|
12345
|
+
import * as path12 from "path";
|
|
12346
|
+
import * as os5 from "os";
|
|
12705
12347
|
function tryExec(command) {
|
|
12706
12348
|
try {
|
|
12707
12349
|
return execSync4(command, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
@@ -12862,8 +12504,8 @@ function checkNpm() {
|
|
|
12862
12504
|
};
|
|
12863
12505
|
}
|
|
12864
12506
|
function checkShivaConfig() {
|
|
12865
|
-
const configDir =
|
|
12866
|
-
const configFile =
|
|
12507
|
+
const configDir = path12.join(os5.homedir(), ".config", "shiva-code");
|
|
12508
|
+
const configFile = path12.join(configDir, "config.json");
|
|
12867
12509
|
if (!fs11.existsSync(configDir)) {
|
|
12868
12510
|
return {
|
|
12869
12511
|
name: "SHIVA Config",
|
|
@@ -12887,7 +12529,7 @@ function checkShivaConfig() {
|
|
|
12887
12529
|
};
|
|
12888
12530
|
}
|
|
12889
12531
|
function checkClaudeProjects() {
|
|
12890
|
-
const claudeDir =
|
|
12532
|
+
const claudeDir = path12.join(os5.homedir(), ".claude", "projects");
|
|
12891
12533
|
if (!fs11.existsSync(claudeDir)) {
|
|
12892
12534
|
return {
|
|
12893
12535
|
name: "Claude Projects",
|
|
@@ -12898,7 +12540,7 @@ function checkClaudeProjects() {
|
|
|
12898
12540
|
}
|
|
12899
12541
|
try {
|
|
12900
12542
|
const projects = fs11.readdirSync(claudeDir).filter(
|
|
12901
|
-
(f) => fs11.statSync(
|
|
12543
|
+
(f) => fs11.statSync(path12.join(claudeDir, f)).isDirectory()
|
|
12902
12544
|
);
|
|
12903
12545
|
return {
|
|
12904
12546
|
name: "Claude Projects",
|
|
@@ -12931,11 +12573,11 @@ function checkTmux() {
|
|
|
12931
12573
|
};
|
|
12932
12574
|
}
|
|
12933
12575
|
function getSystemInfo() {
|
|
12934
|
-
const totalMem =
|
|
12576
|
+
const totalMem = os5.totalmem();
|
|
12935
12577
|
const memGB = (totalMem / (1024 * 1024 * 1024)).toFixed(1);
|
|
12936
12578
|
return {
|
|
12937
|
-
os: `${
|
|
12938
|
-
arch:
|
|
12579
|
+
os: `${os5.type()} ${os5.release()}`,
|
|
12580
|
+
arch: os5.arch(),
|
|
12939
12581
|
memory: `${memGB} GB`
|
|
12940
12582
|
};
|
|
12941
12583
|
}
|
|
@@ -13027,14 +12669,14 @@ var doctorCommand = new Command27("doctor").description("System-Check f\xFCr SHI
|
|
|
13027
12669
|
import { Command as Command28 } from "commander";
|
|
13028
12670
|
import { execSync as execSync5, spawn as spawn6 } from "child_process";
|
|
13029
12671
|
import * as fs12 from "fs";
|
|
13030
|
-
import * as
|
|
12672
|
+
import * as path13 from "path";
|
|
13031
12673
|
import { fileURLToPath } from "url";
|
|
13032
12674
|
var __filename = fileURLToPath(import.meta.url);
|
|
13033
|
-
var __dirname =
|
|
12675
|
+
var __dirname = path13.dirname(__filename);
|
|
13034
12676
|
var PACKAGE_NAME = "shiva-code";
|
|
13035
12677
|
function getCurrentVersion() {
|
|
13036
12678
|
try {
|
|
13037
|
-
const packageJsonPath =
|
|
12679
|
+
const packageJsonPath = path13.resolve(__dirname, "../../package.json");
|
|
13038
12680
|
if (fs12.existsSync(packageJsonPath)) {
|
|
13039
12681
|
const packageJson = JSON.parse(fs12.readFileSync(packageJsonPath, "utf-8"));
|
|
13040
12682
|
return packageJson.version || "0.0.0";
|
|
@@ -13179,8 +12821,8 @@ var selfUpdateCommand = new Command28("self-update").description('Alias f\xFCr "
|
|
|
13179
12821
|
|
|
13180
12822
|
// src/commands/system/telemetry.ts
|
|
13181
12823
|
import { Command as Command29 } from "commander";
|
|
13182
|
-
import
|
|
13183
|
-
var telemetryConfig = new
|
|
12824
|
+
import Conf4 from "conf";
|
|
12825
|
+
var telemetryConfig = new Conf4({
|
|
13184
12826
|
projectName: "shiva-code",
|
|
13185
12827
|
projectSuffix: "",
|
|
13186
12828
|
configName: "telemetry",
|
|
@@ -13434,9 +13076,9 @@ complete -F _shiva_completions shiva
|
|
|
13434
13076
|
}
|
|
13435
13077
|
async function installBashCompletion() {
|
|
13436
13078
|
const fs15 = await import("fs");
|
|
13437
|
-
const
|
|
13438
|
-
const
|
|
13439
|
-
const bashrcPath =
|
|
13079
|
+
const os7 = await import("os");
|
|
13080
|
+
const path15 = await import("path");
|
|
13081
|
+
const bashrcPath = path15.join(os7.homedir(), ".bashrc");
|
|
13440
13082
|
const completionScript = generateBashCompletion();
|
|
13441
13083
|
const marker = "# SHIVA Code Bash Completion";
|
|
13442
13084
|
try {
|
|
@@ -13577,9 +13219,9 @@ compdef _shiva shiva
|
|
|
13577
13219
|
}
|
|
13578
13220
|
async function installZshCompletion() {
|
|
13579
13221
|
const fs15 = await import("fs");
|
|
13580
|
-
const
|
|
13581
|
-
const
|
|
13582
|
-
const zshrcPath =
|
|
13222
|
+
const os7 = await import("os");
|
|
13223
|
+
const path15 = await import("path");
|
|
13224
|
+
const zshrcPath = path15.join(os7.homedir(), ".zshrc");
|
|
13583
13225
|
const completionScript = generateZshCompletion();
|
|
13584
13226
|
const marker = "# SHIVA Code Zsh Completion";
|
|
13585
13227
|
try {
|
|
@@ -13682,10 +13324,10 @@ complete -c shiva -n "__fish_seen_subcommand_from stats" -l json -d "JSON Output
|
|
|
13682
13324
|
}
|
|
13683
13325
|
async function installFishCompletion() {
|
|
13684
13326
|
const fs15 = await import("fs");
|
|
13685
|
-
const
|
|
13686
|
-
const
|
|
13687
|
-
const fishCompletionsDir =
|
|
13688
|
-
const fishCompletionPath =
|
|
13327
|
+
const os7 = await import("os");
|
|
13328
|
+
const path15 = await import("path");
|
|
13329
|
+
const fishCompletionsDir = path15.join(os7.homedir(), ".config", "fish", "completions");
|
|
13330
|
+
const fishCompletionPath = path15.join(fishCompletionsDir, "shiva.fish");
|
|
13689
13331
|
const completionScript = generateFishCompletion();
|
|
13690
13332
|
try {
|
|
13691
13333
|
if (!fs15.existsSync(fishCompletionsDir)) {
|
|
@@ -14093,8 +13735,8 @@ dockerCommand.action(() => {
|
|
|
14093
13735
|
// src/commands/advanced/workflow.ts
|
|
14094
13736
|
import { Command as Command33 } from "commander";
|
|
14095
13737
|
import * as fs13 from "fs";
|
|
14096
|
-
import * as
|
|
14097
|
-
import * as
|
|
13738
|
+
import * as path14 from "path";
|
|
13739
|
+
import * as os6 from "os";
|
|
14098
13740
|
import ora20 from "ora";
|
|
14099
13741
|
import inquirer12 from "inquirer";
|
|
14100
13742
|
var builtInWorkflows = {
|
|
@@ -14253,7 +13895,7 @@ workflowCommand.command("delete").alias("rm").description("Workflow l\xF6schen")
|
|
|
14253
13895
|
log.success(`Workflow "${name}" gel\xF6scht`);
|
|
14254
13896
|
});
|
|
14255
13897
|
function getWorkflowsPath() {
|
|
14256
|
-
return
|
|
13898
|
+
return path14.join(os6.homedir(), ".shiva", "workflows.json");
|
|
14257
13899
|
}
|
|
14258
13900
|
function loadCustomWorkflows() {
|
|
14259
13901
|
const filepath = getWorkflowsPath();
|
|
@@ -14269,7 +13911,7 @@ function loadCustomWorkflows() {
|
|
|
14269
13911
|
}
|
|
14270
13912
|
function saveCustomWorkflow(name, workflow) {
|
|
14271
13913
|
const filepath = getWorkflowsPath();
|
|
14272
|
-
const dir =
|
|
13914
|
+
const dir = path14.dirname(filepath);
|
|
14273
13915
|
if (!fs13.existsSync(dir)) {
|
|
14274
13916
|
fs13.mkdirSync(dir, { recursive: true });
|
|
14275
13917
|
}
|
|
@@ -14372,9 +14014,9 @@ async function executeStep(step) {
|
|
|
14372
14014
|
// src/commands/advanced/hook.ts
|
|
14373
14015
|
import { Command as Command34 } from "commander";
|
|
14374
14016
|
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 =
|
|
14017
|
+
import { homedir as homedir7 } from "os";
|
|
14018
|
+
import { join as join12 } from "path";
|
|
14019
|
+
var CLAUDE_SETTINGS_PATH = join12(homedir7(), ".claude", "settings.json");
|
|
14378
14020
|
function getClaudeSettings() {
|
|
14379
14021
|
if (!existsSync21(CLAUDE_SETTINGS_PATH)) {
|
|
14380
14022
|
return {};
|
|
@@ -14387,7 +14029,7 @@ function getClaudeSettings() {
|
|
|
14387
14029
|
}
|
|
14388
14030
|
}
|
|
14389
14031
|
function saveClaudeSettings(settings) {
|
|
14390
|
-
const dir =
|
|
14032
|
+
const dir = join12(homedir7(), ".claude");
|
|
14391
14033
|
if (!existsSync21(dir)) {
|
|
14392
14034
|
mkdirSync6(dir, { recursive: true });
|
|
14393
14035
|
}
|
|
@@ -14408,7 +14050,7 @@ function removeShivaHooks(eventHooks) {
|
|
|
14408
14050
|
var hookCommand = new Command34("hook").description("Claude Code Hook Integration verwalten");
|
|
14409
14051
|
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
14052
|
log.brand();
|
|
14411
|
-
const claudePath =
|
|
14053
|
+
const claudePath = join12(homedir7(), ".claude");
|
|
14412
14054
|
if (!existsSync21(claudePath)) {
|
|
14413
14055
|
log.error("Claude Code nicht gefunden");
|
|
14414
14056
|
log.newline();
|
|
@@ -14646,8 +14288,8 @@ hookCommand.command("inject-context").description("GitHub Context in Session inj
|
|
|
14646
14288
|
return;
|
|
14647
14289
|
}
|
|
14648
14290
|
if (hasShivaDir(projectPath)) {
|
|
14649
|
-
const
|
|
14650
|
-
if (!
|
|
14291
|
+
const config = getProjectConfig(projectPath);
|
|
14292
|
+
if (!config.autoInjectContext) {
|
|
14651
14293
|
console.log(JSON.stringify({}));
|
|
14652
14294
|
return;
|
|
14653
14295
|
}
|
|
@@ -14718,8 +14360,8 @@ hookCommand.command("branch-switch").description("Branch-Wechsel behandeln (f\xF
|
|
|
14718
14360
|
}
|
|
14719
14361
|
});
|
|
14720
14362
|
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 (!
|
|
14363
|
+
const config = packageScanner.getConfig();
|
|
14364
|
+
if (!config.enabled) {
|
|
14723
14365
|
console.log(JSON.stringify({ hookSpecificOutput: null }));
|
|
14724
14366
|
return;
|
|
14725
14367
|
}
|
|
@@ -14739,6 +14381,85 @@ hookCommand.command("scan-command").description("Scanne Bash-Befehle auf Package
|
|
|
14739
14381
|
console.log(JSON.stringify({ hookSpecificOutput: null }));
|
|
14740
14382
|
}
|
|
14741
14383
|
});
|
|
14384
|
+
hookCommand.command("push").description("Hooks in Cloud sichern").action(async () => {
|
|
14385
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
14386
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14387
|
+
if (!isAuthenticated2()) {
|
|
14388
|
+
log.error("Nicht angemeldet");
|
|
14389
|
+
log.info("Anmelden mit: shiva login");
|
|
14390
|
+
return;
|
|
14391
|
+
}
|
|
14392
|
+
const settings = getClaudeSettings();
|
|
14393
|
+
if (!settings.hooks) {
|
|
14394
|
+
log.warn("Keine lokalen Hooks konfiguriert");
|
|
14395
|
+
return;
|
|
14396
|
+
}
|
|
14397
|
+
try {
|
|
14398
|
+
await api2.updateHooks(settings.hooks);
|
|
14399
|
+
log.success("Hooks in Cloud gesichert");
|
|
14400
|
+
} catch (error) {
|
|
14401
|
+
log.error(error instanceof Error ? error.message : "Fehler beim Sichern");
|
|
14402
|
+
}
|
|
14403
|
+
});
|
|
14404
|
+
hookCommand.command("pull").description("Hooks aus Cloud laden").option("-f, --force", "Lokale Hooks \xFCberschreiben").action(async (options) => {
|
|
14405
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
14406
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14407
|
+
if (!isAuthenticated2()) {
|
|
14408
|
+
log.error("Nicht angemeldet");
|
|
14409
|
+
log.info("Anmelden mit: shiva login");
|
|
14410
|
+
return;
|
|
14411
|
+
}
|
|
14412
|
+
const settings = getClaudeSettings();
|
|
14413
|
+
if (settings.hooks && !options.force) {
|
|
14414
|
+
log.warn("Lokale Hooks existieren bereits");
|
|
14415
|
+
log.info("Mit --force \xFCberschreiben");
|
|
14416
|
+
return;
|
|
14417
|
+
}
|
|
14418
|
+
try {
|
|
14419
|
+
const result = await api2.getHooks();
|
|
14420
|
+
if (!result.hooks || Object.keys(result.hooks).length === 0) {
|
|
14421
|
+
log.info("Keine Hooks in Cloud gefunden");
|
|
14422
|
+
return;
|
|
14423
|
+
}
|
|
14424
|
+
settings.hooks = result.hooks;
|
|
14425
|
+
saveClaudeSettings(settings);
|
|
14426
|
+
log.success("Hooks aus Cloud geladen");
|
|
14427
|
+
log.newline();
|
|
14428
|
+
log.info("Aktive Hooks:");
|
|
14429
|
+
for (const [event, hooks] of Object.entries(result.hooks)) {
|
|
14430
|
+
log.tree.item(`${event}: ${Array.isArray(hooks) ? hooks.length : 1} Hook(s)`);
|
|
14431
|
+
}
|
|
14432
|
+
} catch (error) {
|
|
14433
|
+
log.error(error instanceof Error ? error.message : "Fehler beim Laden");
|
|
14434
|
+
}
|
|
14435
|
+
});
|
|
14436
|
+
hookCommand.command("sync").description("Hooks mit Cloud synchronisieren").action(async () => {
|
|
14437
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
14438
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14439
|
+
if (!isAuthenticated2()) {
|
|
14440
|
+
log.error("Nicht angemeldet");
|
|
14441
|
+
log.info("Anmelden mit: shiva login");
|
|
14442
|
+
return;
|
|
14443
|
+
}
|
|
14444
|
+
const settings = getClaudeSettings();
|
|
14445
|
+
try {
|
|
14446
|
+
if (settings.hooks) {
|
|
14447
|
+
await api2.updateHooks(settings.hooks);
|
|
14448
|
+
log.success("Lokale Hooks \u2192 Cloud");
|
|
14449
|
+
}
|
|
14450
|
+
const result = await api2.getHooks();
|
|
14451
|
+
if (result.hooks && Object.keys(result.hooks).length > 0) {
|
|
14452
|
+
const merged = { ...result.hooks, ...settings.hooks };
|
|
14453
|
+
settings.hooks = merged;
|
|
14454
|
+
saveClaudeSettings(settings);
|
|
14455
|
+
log.success("Cloud Hooks \u2192 Lokal (merged)");
|
|
14456
|
+
}
|
|
14457
|
+
log.newline();
|
|
14458
|
+
log.success("Hooks synchronisiert");
|
|
14459
|
+
} catch (error) {
|
|
14460
|
+
log.error(error instanceof Error ? error.message : "Fehler beim Synchronisieren");
|
|
14461
|
+
}
|
|
14462
|
+
});
|
|
14742
14463
|
|
|
14743
14464
|
// src/commands/advanced/package.ts
|
|
14744
14465
|
import { Command as Command35 } from "commander";
|
|
@@ -14889,6 +14610,186 @@ packageCommand.command("start <name>").description("Alle Projekte eines Packages
|
|
|
14889
14610
|
log.error(error instanceof Error ? error.message : "Unbekannter Fehler");
|
|
14890
14611
|
}
|
|
14891
14612
|
});
|
|
14613
|
+
packageCommand.command("push").description("Packages in Cloud sichern").option("-n, --name <name>", "Nur ein bestimmtes Package").action(async (options) => {
|
|
14614
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
14615
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14616
|
+
if (!isAuthenticated2()) {
|
|
14617
|
+
log.error("Nicht angemeldet");
|
|
14618
|
+
log.info("Anmelden mit: shiva login");
|
|
14619
|
+
return;
|
|
14620
|
+
}
|
|
14621
|
+
let packages = getAllPackages();
|
|
14622
|
+
if (options.name) {
|
|
14623
|
+
const found = getPackage(options.name);
|
|
14624
|
+
if (found) {
|
|
14625
|
+
packages = [found];
|
|
14626
|
+
} else {
|
|
14627
|
+
log.error(`Package nicht gefunden: ${options.name}`);
|
|
14628
|
+
return;
|
|
14629
|
+
}
|
|
14630
|
+
}
|
|
14631
|
+
if (packages.length === 0) {
|
|
14632
|
+
log.warn("Keine Packages zum Synchronisieren gefunden");
|
|
14633
|
+
return;
|
|
14634
|
+
}
|
|
14635
|
+
const spinner = ora21("Synchronisiere Packages...").start();
|
|
14636
|
+
let syncedCount = 0;
|
|
14637
|
+
let errorCount = 0;
|
|
14638
|
+
for (const pkg of packages) {
|
|
14639
|
+
try {
|
|
14640
|
+
await api2.syncPackage({
|
|
14641
|
+
name: pkg.name,
|
|
14642
|
+
description: pkg.description,
|
|
14643
|
+
projects: pkg.projects,
|
|
14644
|
+
launchOrder: pkg.launchOrder
|
|
14645
|
+
});
|
|
14646
|
+
syncedCount++;
|
|
14647
|
+
} catch {
|
|
14648
|
+
errorCount++;
|
|
14649
|
+
}
|
|
14650
|
+
}
|
|
14651
|
+
spinner.stop();
|
|
14652
|
+
if (syncedCount > 0) {
|
|
14653
|
+
log.success(`${syncedCount} Packages in Cloud gesichert`);
|
|
14654
|
+
}
|
|
14655
|
+
if (errorCount > 0) {
|
|
14656
|
+
log.warn(`${errorCount} Packages konnten nicht gesichert werden`);
|
|
14657
|
+
}
|
|
14658
|
+
});
|
|
14659
|
+
packageCommand.command("pull").description("Packages aus Cloud laden").option("-f, --force", "Lokale Packages \xFCberschreiben").option("--json", "JSON Output").action(async (options) => {
|
|
14660
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
14661
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14662
|
+
if (!isAuthenticated2()) {
|
|
14663
|
+
log.error("Nicht angemeldet");
|
|
14664
|
+
log.info("Anmelden mit: shiva login");
|
|
14665
|
+
return;
|
|
14666
|
+
}
|
|
14667
|
+
const spinner = ora21("Lade Packages aus Cloud...").start();
|
|
14668
|
+
try {
|
|
14669
|
+
const cloudPackages = await api2.getPackages();
|
|
14670
|
+
spinner.stop();
|
|
14671
|
+
if (options.json) {
|
|
14672
|
+
console.log(JSON.stringify(cloudPackages, null, 2));
|
|
14673
|
+
return;
|
|
14674
|
+
}
|
|
14675
|
+
if (cloudPackages.length === 0) {
|
|
14676
|
+
log.info("Keine Packages in Cloud gefunden");
|
|
14677
|
+
log.dim("Hochladen mit: shiva package push");
|
|
14678
|
+
return;
|
|
14679
|
+
}
|
|
14680
|
+
log.success(`${cloudPackages.length} Packages in Cloud gefunden`);
|
|
14681
|
+
log.newline();
|
|
14682
|
+
const localPackages = getAllPackages();
|
|
14683
|
+
let importedCount = 0;
|
|
14684
|
+
let skippedCount = 0;
|
|
14685
|
+
for (const cloudPkg of cloudPackages) {
|
|
14686
|
+
const localPkg = localPackages.find((p) => p.name.toLowerCase() === cloudPkg.name.toLowerCase());
|
|
14687
|
+
if (localPkg && !options.force) {
|
|
14688
|
+
log.dim(` \u23ED ${cloudPkg.name} (lokal vorhanden, --force zum \xDCberschreiben)`);
|
|
14689
|
+
skippedCount++;
|
|
14690
|
+
continue;
|
|
14691
|
+
}
|
|
14692
|
+
try {
|
|
14693
|
+
if (localPkg) {
|
|
14694
|
+
deletePackage(localPkg.name);
|
|
14695
|
+
}
|
|
14696
|
+
createPackage(cloudPkg.name, cloudPkg.description, cloudPkg.launchOrder);
|
|
14697
|
+
for (const projectPath of cloudPkg.projects) {
|
|
14698
|
+
try {
|
|
14699
|
+
addProjectToPackage(cloudPkg.name, projectPath);
|
|
14700
|
+
} catch {
|
|
14701
|
+
}
|
|
14702
|
+
}
|
|
14703
|
+
log.success(` \u2713 ${cloudPkg.name} importiert`);
|
|
14704
|
+
importedCount++;
|
|
14705
|
+
} catch (error) {
|
|
14706
|
+
log.warn(` \u2717 ${cloudPkg.name}: ${error instanceof Error ? error.message : "Fehler"}`);
|
|
14707
|
+
}
|
|
14708
|
+
}
|
|
14709
|
+
log.newline();
|
|
14710
|
+
if (importedCount > 0) {
|
|
14711
|
+
log.success(`${importedCount} Packages importiert`);
|
|
14712
|
+
}
|
|
14713
|
+
if (skippedCount > 0) {
|
|
14714
|
+
log.dim(`${skippedCount} \xFCbersprungen (bereits lokal vorhanden)`);
|
|
14715
|
+
}
|
|
14716
|
+
} catch (error) {
|
|
14717
|
+
spinner.stop();
|
|
14718
|
+
log.error(error instanceof Error ? error.message : "Fehler beim Laden");
|
|
14719
|
+
}
|
|
14720
|
+
});
|
|
14721
|
+
packageCommand.command("sync").description("Packages mit Cloud synchronisieren").action(async () => {
|
|
14722
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
14723
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14724
|
+
if (!isAuthenticated2()) {
|
|
14725
|
+
log.error("Nicht angemeldet");
|
|
14726
|
+
log.info("Anmelden mit: shiva login");
|
|
14727
|
+
return;
|
|
14728
|
+
}
|
|
14729
|
+
const spinner = ora21("Synchronisiere Packages...").start();
|
|
14730
|
+
const localPackages = getAllPackages();
|
|
14731
|
+
let pushedCount = 0;
|
|
14732
|
+
for (const pkg of localPackages) {
|
|
14733
|
+
try {
|
|
14734
|
+
await api2.syncPackage({
|
|
14735
|
+
name: pkg.name,
|
|
14736
|
+
description: pkg.description,
|
|
14737
|
+
projects: pkg.projects,
|
|
14738
|
+
launchOrder: pkg.launchOrder
|
|
14739
|
+
});
|
|
14740
|
+
pushedCount++;
|
|
14741
|
+
} catch {
|
|
14742
|
+
}
|
|
14743
|
+
}
|
|
14744
|
+
let pulledCount = 0;
|
|
14745
|
+
try {
|
|
14746
|
+
const cloudPackages = await api2.getPackages();
|
|
14747
|
+
for (const cloudPkg of cloudPackages) {
|
|
14748
|
+
const localPkg = localPackages.find((p) => p.name.toLowerCase() === cloudPkg.name.toLowerCase());
|
|
14749
|
+
if (!localPkg) {
|
|
14750
|
+
try {
|
|
14751
|
+
createPackage(cloudPkg.name, cloudPkg.description, cloudPkg.launchOrder);
|
|
14752
|
+
for (const projectPath of cloudPkg.projects) {
|
|
14753
|
+
try {
|
|
14754
|
+
addProjectToPackage(cloudPkg.name, projectPath);
|
|
14755
|
+
} catch {
|
|
14756
|
+
}
|
|
14757
|
+
}
|
|
14758
|
+
pulledCount++;
|
|
14759
|
+
} catch {
|
|
14760
|
+
}
|
|
14761
|
+
}
|
|
14762
|
+
}
|
|
14763
|
+
} catch {
|
|
14764
|
+
}
|
|
14765
|
+
spinner.stop();
|
|
14766
|
+
log.success("Packages synchronisiert");
|
|
14767
|
+
log.newline();
|
|
14768
|
+
log.tree.item(`${pushedCount} lokale Packages \u2192 Cloud`);
|
|
14769
|
+
if (pulledCount > 0) {
|
|
14770
|
+
log.tree.item(`${pulledCount} neue Packages \u2190 Cloud`);
|
|
14771
|
+
}
|
|
14772
|
+
log.tree.item(`${localPackages.length + pulledCount} Packages total`);
|
|
14773
|
+
});
|
|
14774
|
+
packageCommand.command("cloud-delete <name>").description("Package aus Cloud l\xF6schen").action(async (name) => {
|
|
14775
|
+
const { api: api2 } = await import("./client-2L7NWNCZ.js");
|
|
14776
|
+
const { isAuthenticated: isAuthenticated2 } = await import("./config-FGMZONWV.js");
|
|
14777
|
+
if (!isAuthenticated2()) {
|
|
14778
|
+
log.error("Nicht angemeldet");
|
|
14779
|
+
log.info("Anmelden mit: shiva login");
|
|
14780
|
+
return;
|
|
14781
|
+
}
|
|
14782
|
+
try {
|
|
14783
|
+
const result = await api2.deleteCloudPackage(name);
|
|
14784
|
+
if (result.success) {
|
|
14785
|
+
log.success(`Package "${name}" aus Cloud gel\xF6scht`);
|
|
14786
|
+
} else {
|
|
14787
|
+
log.error(result.message || "Fehler beim L\xF6schen");
|
|
14788
|
+
}
|
|
14789
|
+
} catch (error) {
|
|
14790
|
+
log.error(error instanceof Error ? error.message : "Fehler beim L\xF6schen");
|
|
14791
|
+
}
|
|
14792
|
+
});
|
|
14892
14793
|
function listPackages() {
|
|
14893
14794
|
const packages = getAllPackages();
|
|
14894
14795
|
const stats = getPackageStats();
|
|
@@ -14929,7 +14830,7 @@ function listPackages() {
|
|
|
14929
14830
|
|
|
14930
14831
|
// src/index.ts
|
|
14931
14832
|
var program = new Command36();
|
|
14932
|
-
program.name("shiva").description("SHIVA Code - Control Station for Claude Code").version("0.5.
|
|
14833
|
+
program.name("shiva").description("SHIVA Code - Control Station for Claude Code").version("0.5.4");
|
|
14933
14834
|
program.addCommand(loginCommand);
|
|
14934
14835
|
program.addCommand(logoutCommand);
|
|
14935
14836
|
program.addCommand(sessionsCommand);
|