@fluxra-ai/fluxra-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +274 -0
- package/bin/fluxra +6 -0
- package/dist/cli/command-context.d.ts +17 -0
- package/dist/cli/command-context.d.ts.map +1 -0
- package/dist/cli/command-context.js +26 -0
- package/dist/cli/command-context.js.map +1 -0
- package/dist/cli/commands/auth/index.d.ts +3 -0
- package/dist/cli/commands/auth/index.d.ts.map +1 -0
- package/dist/cli/commands/auth/index.js +165 -0
- package/dist/cli/commands/auth/index.js.map +1 -0
- package/dist/cli/commands/chat/index.d.ts +3 -0
- package/dist/cli/commands/chat/index.d.ts.map +1 -0
- package/dist/cli/commands/chat/index.js +1201 -0
- package/dist/cli/commands/chat/index.js.map +1 -0
- package/dist/cli/commands/config/index.d.ts +3 -0
- package/dist/cli/commands/config/index.d.ts.map +1 -0
- package/dist/cli/commands/config/index.js +66 -0
- package/dist/cli/commands/config/index.js.map +1 -0
- package/dist/cli/commands/help.d.ts +7 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +106 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/local/doctor.d.ts +26 -0
- package/dist/cli/commands/local/doctor.d.ts.map +1 -0
- package/dist/cli/commands/local/doctor.js +265 -0
- package/dist/cli/commands/local/doctor.js.map +1 -0
- package/dist/cli/commands/local/export.d.ts +41 -0
- package/dist/cli/commands/local/export.d.ts.map +1 -0
- package/dist/cli/commands/local/export.js +83 -0
- package/dist/cli/commands/local/export.js.map +1 -0
- package/dist/cli/commands/local/index.d.ts +6 -0
- package/dist/cli/commands/local/index.d.ts.map +1 -0
- package/dist/cli/commands/local/index.js +116 -0
- package/dist/cli/commands/local/index.js.map +1 -0
- package/dist/cli/commands/local/inspect.d.ts +42 -0
- package/dist/cli/commands/local/inspect.d.ts.map +1 -0
- package/dist/cli/commands/local/inspect.js +125 -0
- package/dist/cli/commands/local/inspect.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +8 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +253 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/profile/index.d.ts +3 -0
- package/dist/cli/commands/profile/index.d.ts.map +1 -0
- package/dist/cli/commands/profile/index.js +114 -0
- package/dist/cli/commands/profile/index.js.map +1 -0
- package/dist/cli/commands/schema.d.ts +7 -0
- package/dist/cli/commands/schema.d.ts.map +1 -0
- package/dist/cli/commands/schema.js +33 -0
- package/dist/cli/commands/schema.js.map +1 -0
- package/dist/cli/errors.d.ts +16 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +15 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/fluxra.d.ts +9 -0
- package/dist/cli/fluxra.d.ts.map +1 -0
- package/dist/cli/fluxra.js +55 -0
- package/dist/cli/fluxra.js.map +1 -0
- package/dist/cli/helpers.d.ts +13 -0
- package/dist/cli/helpers.d.ts.map +1 -0
- package/dist/cli/helpers.js +32 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/output.d.ts +14 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +55 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/version.d.ts +6 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +8 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/core/auth/auth-service.d.ts +35 -0
- package/dist/core/auth/auth-service.d.ts.map +1 -0
- package/dist/core/auth/auth-service.js +116 -0
- package/dist/core/auth/auth-service.js.map +1 -0
- package/dist/core/config/global-config.d.ts +38 -0
- package/dist/core/config/global-config.d.ts.map +1 -0
- package/dist/core/config/global-config.js +75 -0
- package/dist/core/config/global-config.js.map +1 -0
- package/dist/core/errors/error-model.d.ts +48 -0
- package/dist/core/errors/error-model.d.ts.map +1 -0
- package/dist/core/errors/error-model.js +152 -0
- package/dist/core/errors/error-model.js.map +1 -0
- package/dist/core/filesystem/paths.d.ts +45 -0
- package/dist/core/filesystem/paths.d.ts.map +1 -0
- package/dist/core/filesystem/paths.js +77 -0
- package/dist/core/filesystem/paths.js.map +1 -0
- package/dist/core/http/auth-api.d.ts +71 -0
- package/dist/core/http/auth-api.d.ts.map +1 -0
- package/dist/core/http/auth-api.js +91 -0
- package/dist/core/http/auth-api.js.map +1 -0
- package/dist/core/http/block-api.d.ts +37 -0
- package/dist/core/http/block-api.d.ts.map +1 -0
- package/dist/core/http/block-api.js +36 -0
- package/dist/core/http/block-api.js.map +1 -0
- package/dist/core/http/chat-api.d.ts +41 -0
- package/dist/core/http/chat-api.d.ts.map +1 -0
- package/dist/core/http/chat-api.js +88 -0
- package/dist/core/http/chat-api.js.map +1 -0
- package/dist/core/http/conversation-management-api.d.ts +65 -0
- package/dist/core/http/conversation-management-api.d.ts.map +1 -0
- package/dist/core/http/conversation-management-api.js +59 -0
- package/dist/core/http/conversation-management-api.js.map +1 -0
- package/dist/core/http/directory-api.d.ts +32 -0
- package/dist/core/http/directory-api.d.ts.map +1 -0
- package/dist/core/http/directory-api.js +36 -0
- package/dist/core/http/directory-api.js.map +1 -0
- package/dist/core/http/directory-profile-api.d.ts +32 -0
- package/dist/core/http/directory-profile-api.d.ts.map +1 -0
- package/dist/core/http/directory-profile-api.js +39 -0
- package/dist/core/http/directory-profile-api.js.map +1 -0
- package/dist/core/http/http-client.d.ts +41 -0
- package/dist/core/http/http-client.d.ts.map +1 -0
- package/dist/core/http/http-client.js +127 -0
- package/dist/core/http/http-client.js.map +1 -0
- package/dist/core/http/message-api.d.ts +55 -0
- package/dist/core/http/message-api.d.ts.map +1 -0
- package/dist/core/http/message-api.js +64 -0
- package/dist/core/http/message-api.js.map +1 -0
- package/dist/core/http/rate-limit.d.ts +22 -0
- package/dist/core/http/rate-limit.d.ts.map +1 -0
- package/dist/core/http/rate-limit.js +66 -0
- package/dist/core/http/rate-limit.js.map +1 -0
- package/dist/core/http/token-lifecycle.d.ts +18 -0
- package/dist/core/http/token-lifecycle.d.ts.map +1 -0
- package/dist/core/http/token-lifecycle.js +73 -0
- package/dist/core/http/token-lifecycle.js.map +1 -0
- package/dist/core/locking/profile-lock.d.ts +32 -0
- package/dist/core/locking/profile-lock.d.ts.map +1 -0
- package/dist/core/locking/profile-lock.js +104 -0
- package/dist/core/locking/profile-lock.js.map +1 -0
- package/dist/core/profiles/profile-service.d.ts +35 -0
- package/dist/core/profiles/profile-service.d.ts.map +1 -0
- package/dist/core/profiles/profile-service.js +119 -0
- package/dist/core/profiles/profile-service.js.map +1 -0
- package/dist/core/profiles/profile-types.d.ts +28 -0
- package/dist/core/profiles/profile-types.d.ts.map +1 -0
- package/dist/core/profiles/profile-types.js +13 -0
- package/dist/core/profiles/profile-types.js.map +1 -0
- package/dist/core/secrets/secrets-service.d.ts +25 -0
- package/dist/core/secrets/secrets-service.d.ts.map +1 -0
- package/dist/core/secrets/secrets-service.js +67 -0
- package/dist/core/secrets/secrets-service.js.map +1 -0
- package/dist/core/secrets/secrets-types.d.ts +29 -0
- package/dist/core/secrets/secrets-types.d.ts.map +1 -0
- package/dist/core/secrets/secrets-types.js +33 -0
- package/dist/core/secrets/secrets-types.js.map +1 -0
- package/dist/core/sqlite/chat-schema.d.ts +14 -0
- package/dist/core/sqlite/chat-schema.d.ts.map +1 -0
- package/dist/core/sqlite/chat-schema.js +172 -0
- package/dist/core/sqlite/chat-schema.js.map +1 -0
- package/dist/core/sqlite/core-schema.d.ts +14 -0
- package/dist/core/sqlite/core-schema.d.ts.map +1 -0
- package/dist/core/sqlite/core-schema.js +54 -0
- package/dist/core/sqlite/core-schema.js.map +1 -0
- package/dist/core/sqlite/database.d.ts +40 -0
- package/dist/core/sqlite/database.d.ts.map +1 -0
- package/dist/core/sqlite/database.js +68 -0
- package/dist/core/sqlite/database.js.map +1 -0
- package/dist/core/sqlite/migrations.d.ts +22 -0
- package/dist/core/sqlite/migrations.d.ts.map +1 -0
- package/dist/core/sqlite/migrations.js +64 -0
- package/dist/core/sqlite/migrations.js.map +1 -0
- package/dist/modules/chat/inbox/conversation-service.d.ts +35 -0
- package/dist/modules/chat/inbox/conversation-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/conversation-service.js +54 -0
- package/dist/modules/chat/inbox/conversation-service.js.map +1 -0
- package/dist/modules/chat/inbox/history-service.d.ts +25 -0
- package/dist/modules/chat/inbox/history-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/history-service.js +57 -0
- package/dist/modules/chat/inbox/history-service.js.map +1 -0
- package/dist/modules/chat/inbox/index.d.ts +9 -0
- package/dist/modules/chat/inbox/index.d.ts.map +1 -0
- package/dist/modules/chat/inbox/index.js +9 -0
- package/dist/modules/chat/inbox/index.js.map +1 -0
- package/dist/modules/chat/inbox/read-service.d.ts +36 -0
- package/dist/modules/chat/inbox/read-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/read-service.js +91 -0
- package/dist/modules/chat/inbox/read-service.js.map +1 -0
- package/dist/modules/chat/inbox/search-service.d.ts +20 -0
- package/dist/modules/chat/inbox/search-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/search-service.js +23 -0
- package/dist/modules/chat/inbox/search-service.js.map +1 -0
- package/dist/modules/chat/inbox/unread-service.d.ts +38 -0
- package/dist/modules/chat/inbox/unread-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/unread-service.js +65 -0
- package/dist/modules/chat/inbox/unread-service.js.map +1 -0
- package/dist/modules/chat/render/message-render.d.ts +35 -0
- package/dist/modules/chat/render/message-render.d.ts.map +1 -0
- package/dist/modules/chat/render/message-render.js +129 -0
- package/dist/modules/chat/render/message-render.js.map +1 -0
- package/dist/modules/chat/send/conversation-service.d.ts +53 -0
- package/dist/modules/chat/send/conversation-service.d.ts.map +1 -0
- package/dist/modules/chat/send/conversation-service.js +110 -0
- package/dist/modules/chat/send/conversation-service.js.map +1 -0
- package/dist/modules/chat/send/directory-cache-service.d.ts +37 -0
- package/dist/modules/chat/send/directory-cache-service.d.ts.map +1 -0
- package/dist/modules/chat/send/directory-cache-service.js +49 -0
- package/dist/modules/chat/send/directory-cache-service.js.map +1 -0
- package/dist/modules/chat/send/send-service.d.ts +36 -0
- package/dist/modules/chat/send/send-service.d.ts.map +1 -0
- package/dist/modules/chat/send/send-service.js +113 -0
- package/dist/modules/chat/send/send-service.js.map +1 -0
- package/dist/modules/chat/store/conversation-repo.d.ts +53 -0
- package/dist/modules/chat/store/conversation-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/conversation-repo.js +75 -0
- package/dist/modules/chat/store/conversation-repo.js.map +1 -0
- package/dist/modules/chat/store/directory-cache-repo.d.ts +41 -0
- package/dist/modules/chat/store/directory-cache-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/directory-cache-repo.js +64 -0
- package/dist/modules/chat/store/directory-cache-repo.js.map +1 -0
- package/dist/modules/chat/store/job-repo.d.ts +72 -0
- package/dist/modules/chat/store/job-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/job-repo.js +140 -0
- package/dist/modules/chat/store/job-repo.js.map +1 -0
- package/dist/modules/chat/store/message-repo.d.ts +98 -0
- package/dist/modules/chat/store/message-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/message-repo.js +231 -0
- package/dist/modules/chat/store/message-repo.js.map +1 -0
- package/dist/modules/chat/store/outbox-repo.d.ts +73 -0
- package/dist/modules/chat/store/outbox-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/outbox-repo.js +112 -0
- package/dist/modules/chat/store/outbox-repo.js.map +1 -0
- package/dist/modules/chat/store/read-state-repo.d.ts +83 -0
- package/dist/modules/chat/store/read-state-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/read-state-repo.js +210 -0
- package/dist/modules/chat/store/read-state-repo.js.map +1 -0
- package/dist/modules/chat/store/sync-state-repo.d.ts +45 -0
- package/dist/modules/chat/store/sync-state-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/sync-state-repo.js +67 -0
- package/dist/modules/chat/store/sync-state-repo.js.map +1 -0
- package/dist/modules/chat/sync/backfill.d.ts +13 -0
- package/dist/modules/chat/sync/backfill.d.ts.map +1 -0
- package/dist/modules/chat/sync/backfill.js +37 -0
- package/dist/modules/chat/sync/backfill.js.map +1 -0
- package/dist/modules/chat/sync/cron-manager.d.ts +50 -0
- package/dist/modules/chat/sync/cron-manager.d.ts.map +1 -0
- package/dist/modules/chat/sync/cron-manager.js +164 -0
- package/dist/modules/chat/sync/cron-manager.js.map +1 -0
- package/dist/modules/chat/sync/index.d.ts +8 -0
- package/dist/modules/chat/sync/index.d.ts.map +1 -0
- package/dist/modules/chat/sync/index.js +7 -0
- package/dist/modules/chat/sync/index.js.map +1 -0
- package/dist/modules/chat/sync/job-logger.d.ts +44 -0
- package/dist/modules/chat/sync/job-logger.d.ts.map +1 -0
- package/dist/modules/chat/sync/job-logger.js +139 -0
- package/dist/modules/chat/sync/job-logger.js.map +1 -0
- package/dist/modules/chat/sync/sync-service.d.ts +14 -0
- package/dist/modules/chat/sync/sync-service.d.ts.map +1 -0
- package/dist/modules/chat/sync/sync-service.js +174 -0
- package/dist/modules/chat/sync/sync-service.js.map +1 -0
- package/dist/modules/chat/sync/sync-status.d.ts +14 -0
- package/dist/modules/chat/sync/sync-status.d.ts.map +1 -0
- package/dist/modules/chat/sync/sync-status.js +77 -0
- package/dist/modules/chat/sync/sync-status.js.map +1 -0
- package/dist/modules/chat/sync/sync-types.d.ts +80 -0
- package/dist/modules/chat/sync/sync-types.d.ts.map +1 -0
- package/dist/modules/chat/sync/sync-types.js +5 -0
- package/dist/modules/chat/sync/sync-types.js.map +1 -0
- package/dist/modules/chat/sync/watch-mode.d.ts +45 -0
- package/dist/modules/chat/sync/watch-mode.d.ts.map +1 -0
- package/dist/modules/chat/sync/watch-mode.js +161 -0
- package/dist/modules/chat/sync/watch-mode.js.map +1 -0
- package/package.json +67 -0
- package/tool-schema.json +1039 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile-level locking mechanism
|
|
3
|
+
*/
|
|
4
|
+
export interface ProfileLock {
|
|
5
|
+
profileName: string;
|
|
6
|
+
lockPath: string;
|
|
7
|
+
pid: number;
|
|
8
|
+
acquiredAt: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get the lock file path for a profile
|
|
12
|
+
*/
|
|
13
|
+
export declare function getLockPath(profileName: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Try to acquire a profile lock
|
|
16
|
+
* Returns lock object if successful, null if already locked
|
|
17
|
+
*/
|
|
18
|
+
export declare function acquireLock(profileName: string): ProfileLock | null;
|
|
19
|
+
/**
|
|
20
|
+
* Release a profile lock
|
|
21
|
+
*/
|
|
22
|
+
export declare function releaseLock(lock: ProfileLock): void;
|
|
23
|
+
/**
|
|
24
|
+
* Execute a function with a profile lock
|
|
25
|
+
* Automatically acquires and releases the lock
|
|
26
|
+
*/
|
|
27
|
+
export declare function withLock<T>(profileName: string, fn: () => T): T;
|
|
28
|
+
/**
|
|
29
|
+
* Check if a profile is currently locked
|
|
30
|
+
*/
|
|
31
|
+
export declare function isProfileLocked(profileName: string): boolean;
|
|
32
|
+
//# sourceMappingURL=profile-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-lock.d.ts","sourceRoot":"","sources":["../../../src/core/locking/profile-lock.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAwCnE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAQnD;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,CAAC,GACV,CAAC,CAeH;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAkB5D"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile-level locking mechanism
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { getProfilePath } from '../filesystem/paths.js';
|
|
7
|
+
/**
|
|
8
|
+
* Get the lock file path for a profile
|
|
9
|
+
*/
|
|
10
|
+
export function getLockPath(profileName) {
|
|
11
|
+
return path.join(getProfilePath(profileName), '.lock');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Try to acquire a profile lock
|
|
15
|
+
* Returns lock object if successful, null if already locked
|
|
16
|
+
*/
|
|
17
|
+
export function acquireLock(profileName) {
|
|
18
|
+
const lockPath = getLockPath(profileName);
|
|
19
|
+
const pid = process.pid;
|
|
20
|
+
const acquiredAt = new Date().toISOString();
|
|
21
|
+
// Check if lock exists and is still valid (process alive)
|
|
22
|
+
if (fs.existsSync(lockPath)) {
|
|
23
|
+
try {
|
|
24
|
+
const lockContent = fs.readFileSync(lockPath, 'utf-8');
|
|
25
|
+
const existingLock = JSON.parse(lockContent);
|
|
26
|
+
// Check if the process that created the lock is still running
|
|
27
|
+
try {
|
|
28
|
+
// Signal 0 checks if process exists without actually sending a signal
|
|
29
|
+
process.kill(existingLock.pid, 0);
|
|
30
|
+
// Process is alive, lock is valid
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Process is dead, stale lock - remove it
|
|
35
|
+
console.warn('Removing stale lock file');
|
|
36
|
+
fs.unlinkSync(lockPath);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Invalid lock file - remove it
|
|
41
|
+
fs.unlinkSync(lockPath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Acquire lock
|
|
45
|
+
const lock = {
|
|
46
|
+
profileName,
|
|
47
|
+
lockPath,
|
|
48
|
+
pid,
|
|
49
|
+
acquiredAt,
|
|
50
|
+
};
|
|
51
|
+
fs.writeFileSync(lockPath, JSON.stringify(lock, null, 2), 'utf-8');
|
|
52
|
+
return lock;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Release a profile lock
|
|
56
|
+
*/
|
|
57
|
+
export function releaseLock(lock) {
|
|
58
|
+
try {
|
|
59
|
+
if (fs.existsSync(lock.lockPath)) {
|
|
60
|
+
fs.unlinkSync(lock.lockPath);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Lock already removed, ignore
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Execute a function with a profile lock
|
|
69
|
+
* Automatically acquires and releases the lock
|
|
70
|
+
*/
|
|
71
|
+
export function withLock(profileName, fn) {
|
|
72
|
+
const lock = acquireLock(profileName);
|
|
73
|
+
if (!lock) {
|
|
74
|
+
throw new Error(`Profile '${profileName}' is locked by another process. ` +
|
|
75
|
+
'Wait for the other operation to complete or remove the lock file manually.');
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
return fn();
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
releaseLock(lock);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check if a profile is currently locked
|
|
86
|
+
*/
|
|
87
|
+
export function isProfileLocked(profileName) {
|
|
88
|
+
const lockPath = getLockPath(profileName);
|
|
89
|
+
if (!fs.existsSync(lockPath)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const lockContent = fs.readFileSync(lockPath, 'utf-8');
|
|
94
|
+
const existingLock = JSON.parse(lockContent);
|
|
95
|
+
// Check if process is still running
|
|
96
|
+
process.kill(existingLock.pid, 0);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Stale lock or invalid file
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=profile-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-lock.js","sourceRoot":"","sources":["../../../src/core/locking/profile-lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile service - lifecycle management for profiles
|
|
3
|
+
*/
|
|
4
|
+
import type { ProfileMetadata } from './profile-types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Create a new profile
|
|
7
|
+
*/
|
|
8
|
+
export declare function createProfile(name: string, options?: {
|
|
9
|
+
setDefault?: boolean;
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
environment?: string;
|
|
12
|
+
}): ProfileMetadata;
|
|
13
|
+
/**
|
|
14
|
+
* List all profiles
|
|
15
|
+
*/
|
|
16
|
+
export declare function listProfiles(): Array<{
|
|
17
|
+
name: string;
|
|
18
|
+
metadata: ProfileMetadata;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Set the default profile
|
|
22
|
+
*/
|
|
23
|
+
export declare function useProfile(name: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Show profile details
|
|
26
|
+
*/
|
|
27
|
+
export declare function showProfile(name: string): {
|
|
28
|
+
metadata: ProfileMetadata;
|
|
29
|
+
hasSecrets: boolean;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Get the active profile name (from global config or first available)
|
|
33
|
+
*/
|
|
34
|
+
export declare function getActiveProfile(): string | undefined;
|
|
35
|
+
//# sourceMappingURL=profile-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-service.d.ts","sourceRoot":"","sources":["../../../src/core/profiles/profile-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAI1D;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;IACnD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,eAAe,CAqDvB;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,CAAC,CA4BjF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAO7C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,eAAe,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAa5F;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAGrD"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile service - lifecycle management for profiles
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { getProfilePath, getProfileMetaPath, getStateDir, getModuleDir, ensureDir, } from '../filesystem/paths.js';
|
|
7
|
+
import { ProfileMetadataSchema } from './profile-types.js';
|
|
8
|
+
import { loadGlobalConfig, updateGlobalConfig } from '../config/global-config.js';
|
|
9
|
+
/**
|
|
10
|
+
* Create a new profile
|
|
11
|
+
*/
|
|
12
|
+
export function createProfile(name, options = {}) {
|
|
13
|
+
// Validate profile name
|
|
14
|
+
if (!name || name.trim().length === 0) {
|
|
15
|
+
throw new Error('Profile name cannot be empty');
|
|
16
|
+
}
|
|
17
|
+
if (name.includes('/') || name.includes('\\')) {
|
|
18
|
+
throw new Error('Profile name cannot contain path separators');
|
|
19
|
+
}
|
|
20
|
+
// Check if profile already exists
|
|
21
|
+
const metaPath = getProfileMetaPath(name);
|
|
22
|
+
if (fs.existsSync(metaPath)) {
|
|
23
|
+
throw new Error(`Profile '${name}' already exists`);
|
|
24
|
+
}
|
|
25
|
+
// Create profile directories
|
|
26
|
+
const profileDir = getProfilePath(name);
|
|
27
|
+
ensureDir(profileDir);
|
|
28
|
+
ensureDir(getStateDir(name));
|
|
29
|
+
ensureDir(getModuleDir(name, 'chat'));
|
|
30
|
+
// Create profile metadata
|
|
31
|
+
const now = new Date().toISOString();
|
|
32
|
+
const metadata = {
|
|
33
|
+
name,
|
|
34
|
+
environment: options.environment || 'production',
|
|
35
|
+
baseUrl: options.baseUrl,
|
|
36
|
+
createdAt: now,
|
|
37
|
+
updatedAt: now,
|
|
38
|
+
};
|
|
39
|
+
fs.writeFileSync(metaPath, JSON.stringify(metadata, null, 2), 'utf-8');
|
|
40
|
+
// Create empty secrets file
|
|
41
|
+
const secretsPath = path.join(profileDir, 'secrets.enc.json');
|
|
42
|
+
if (!fs.existsSync(secretsPath)) {
|
|
43
|
+
fs.writeFileSync(secretsPath, JSON.stringify({}, null, 2), 'utf-8');
|
|
44
|
+
// Set strict permissions (owner read/write only)
|
|
45
|
+
try {
|
|
46
|
+
fs.chmodSync(secretsPath, 0o600);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Permission change may not be supported on all systems
|
|
50
|
+
console.warn('Warning: Could not set strict permissions on secrets file');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Set as default if requested
|
|
54
|
+
if (options.setDefault) {
|
|
55
|
+
updateGlobalConfig({ defaultProfile: name });
|
|
56
|
+
}
|
|
57
|
+
return metadata;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* List all profiles
|
|
61
|
+
*/
|
|
62
|
+
export function listProfiles() {
|
|
63
|
+
const profilesDir = getProfilePath(''); // Gets profiles root
|
|
64
|
+
const parentDir = path.dirname(profilesDir);
|
|
65
|
+
if (!fs.existsSync(profilesDir)) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
const entries = fs.readdirSync(profilesDir, { withFileTypes: true });
|
|
69
|
+
const profiles = [];
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
if (entry.isDirectory()) {
|
|
72
|
+
const metaPath = getProfileMetaPath(entry.name);
|
|
73
|
+
if (fs.existsSync(metaPath)) {
|
|
74
|
+
try {
|
|
75
|
+
const raw = fs.readFileSync(metaPath, 'utf-8');
|
|
76
|
+
const parsed = JSON.parse(raw);
|
|
77
|
+
const metadata = ProfileMetadataSchema.parse(parsed);
|
|
78
|
+
profiles.push({ name: entry.name, metadata });
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.warn(`Warning: Could not read profile '${entry.name}': ${error instanceof Error ? error.message : String(error)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return profiles;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Set the default profile
|
|
90
|
+
*/
|
|
91
|
+
export function useProfile(name) {
|
|
92
|
+
const metaPath = getProfileMetaPath(name);
|
|
93
|
+
if (!fs.existsSync(metaPath)) {
|
|
94
|
+
throw new Error(`Profile '${name}' does not exist`);
|
|
95
|
+
}
|
|
96
|
+
updateGlobalConfig({ defaultProfile: name });
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Show profile details
|
|
100
|
+
*/
|
|
101
|
+
export function showProfile(name) {
|
|
102
|
+
const metaPath = getProfileMetaPath(name);
|
|
103
|
+
if (!fs.existsSync(metaPath)) {
|
|
104
|
+
throw new Error(`Profile '${name}' does not exist`);
|
|
105
|
+
}
|
|
106
|
+
const raw = fs.readFileSync(metaPath, 'utf-8');
|
|
107
|
+
const metadata = ProfileMetadataSchema.parse(JSON.parse(raw));
|
|
108
|
+
const secretsPath = path.join(getProfilePath(name), 'secrets.enc.json');
|
|
109
|
+
const hasSecrets = fs.existsSync(secretsPath);
|
|
110
|
+
return { metadata, hasSecrets };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get the active profile name (from global config or first available)
|
|
114
|
+
*/
|
|
115
|
+
export function getActiveProfile() {
|
|
116
|
+
const config = loadGlobalConfig();
|
|
117
|
+
return config.defaultProfile;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=profile-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-service.js","sourceRoot":"","sources":["../../../src/core/profiles/profile-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile metadata types and schema
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
export declare const ProfileMetadataSchema: z.ZodObject<{
|
|
6
|
+
name: z.ZodString;
|
|
7
|
+
agentId: z.ZodOptional<z.ZodString>;
|
|
8
|
+
environment: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
9
|
+
baseUrl: z.ZodOptional<z.ZodString>;
|
|
10
|
+
createdAt: z.ZodString;
|
|
11
|
+
updatedAt: z.ZodString;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
name: string;
|
|
14
|
+
environment: string;
|
|
15
|
+
createdAt: string;
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
agentId?: string | undefined;
|
|
18
|
+
baseUrl?: string | undefined;
|
|
19
|
+
}, {
|
|
20
|
+
name: string;
|
|
21
|
+
createdAt: string;
|
|
22
|
+
updatedAt: string;
|
|
23
|
+
agentId?: string | undefined;
|
|
24
|
+
environment?: string | undefined;
|
|
25
|
+
baseUrl?: string | undefined;
|
|
26
|
+
}>;
|
|
27
|
+
export type ProfileMetadata = z.infer<typeof ProfileMetadataSchema>;
|
|
28
|
+
//# sourceMappingURL=profile-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-types.d.ts","sourceRoot":"","sources":["../../../src/core/profiles/profile-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;EAOhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile metadata types and schema
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
export const ProfileMetadataSchema = z.object({
|
|
6
|
+
name: z.string().min(1).max(100),
|
|
7
|
+
agentId: z.string().optional(),
|
|
8
|
+
environment: z.string().optional().default('production'),
|
|
9
|
+
baseUrl: z.string().url().optional(),
|
|
10
|
+
createdAt: z.string().datetime(),
|
|
11
|
+
updatedAt: z.string().datetime(),
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=profile-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-types.js","sourceRoot":"","sources":["../../../src/core/profiles/profile-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;IACxD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACpC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets service - secure storage and retrieval
|
|
3
|
+
*/
|
|
4
|
+
import type { Secrets } from './secrets-types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Load secrets for a profile
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadSecrets(profileName: string): Secrets;
|
|
9
|
+
/**
|
|
10
|
+
* Save secrets for a profile with strict permissions
|
|
11
|
+
*/
|
|
12
|
+
export declare function saveSecrets(profileName: string, secrets: Secrets): void;
|
|
13
|
+
/**
|
|
14
|
+
* Update specific secret fields
|
|
15
|
+
*/
|
|
16
|
+
export declare function updateSecrets(profileName: string, updates: Partial<Secrets>): Secrets;
|
|
17
|
+
/**
|
|
18
|
+
* Clear all secrets for a profile
|
|
19
|
+
*/
|
|
20
|
+
export declare function clearSecrets(profileName: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Check if secrets file exists
|
|
23
|
+
*/
|
|
24
|
+
export declare function hasSecrets(profileName: string): boolean;
|
|
25
|
+
//# sourceMappingURL=secrets-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets-service.d.ts","sourceRoot":"","sources":["../../../src/core/secrets/secrets-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAGlD;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAiBxD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAevE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAKrF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAEtD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAGvD"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets service - secure storage and retrieval
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { getSecretsPath, getProfilePath, ensureDir } from '../filesystem/paths.js';
|
|
7
|
+
import { SecretsSchema } from './secrets-types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Load secrets for a profile
|
|
10
|
+
*/
|
|
11
|
+
export function loadSecrets(profileName) {
|
|
12
|
+
const secretsPath = getSecretsPath(profileName);
|
|
13
|
+
if (!fs.existsSync(secretsPath)) {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const raw = fs.readFileSync(secretsPath, 'utf-8');
|
|
18
|
+
const parsed = JSON.parse(raw);
|
|
19
|
+
return SecretsSchema.parse(parsed);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof z.ZodError) {
|
|
23
|
+
throw new Error(`Invalid secrets file for profile '${profileName}': ${error.errors.map(e => e.message).join(', ')}`);
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`Failed to load secrets for profile '${profileName}': ${error instanceof Error ? error.message : String(error)}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Save secrets for a profile with strict permissions
|
|
30
|
+
*/
|
|
31
|
+
export function saveSecrets(profileName, secrets) {
|
|
32
|
+
const profileDir = getProfilePath(profileName);
|
|
33
|
+
ensureDir(profileDir);
|
|
34
|
+
const secretsPath = getSecretsPath(profileName);
|
|
35
|
+
const validated = SecretsSchema.parse(secrets);
|
|
36
|
+
// Write with strict permissions (owner read/write only)
|
|
37
|
+
fs.writeFileSync(secretsPath, JSON.stringify(validated, null, 2), 'utf-8');
|
|
38
|
+
try {
|
|
39
|
+
fs.chmodSync(secretsPath, 0o600);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
console.warn('Warning: Could not set strict permissions on secrets file');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Update specific secret fields
|
|
47
|
+
*/
|
|
48
|
+
export function updateSecrets(profileName, updates) {
|
|
49
|
+
const current = loadSecrets(profileName);
|
|
50
|
+
const merged = { ...current, ...updates };
|
|
51
|
+
saveSecrets(profileName, merged);
|
|
52
|
+
return merged;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Clear all secrets for a profile
|
|
56
|
+
*/
|
|
57
|
+
export function clearSecrets(profileName) {
|
|
58
|
+
saveSecrets(profileName, {});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if secrets file exists
|
|
62
|
+
*/
|
|
63
|
+
export function hasSecrets(profileName) {
|
|
64
|
+
const secretsPath = getSecretsPath(profileName);
|
|
65
|
+
return fs.existsSync(secretsPath);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=secrets-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets-service.js","sourceRoot":"","sources":["../../../src/core/secrets/secrets-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB;IAC7C,MAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAEhD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,qCAAqC,WAAW,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,uCAAuC,WAAW,MAAM,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACpI,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,OAAgB;IAC/D,MAAM,UAAU,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC/C,SAAS,CAAC,UAAU,CAAC,CAAC;IAEtB,MAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAE/C,wDAAwD;IACxD,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAE3E,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,WAAmB,EAAE,OAAyB;IAC1E,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IAC1C,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,WAAmB;IAC9C,WAAW,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,WAAmB;IAC5C,MAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAChD,OAAO,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret storage types and schema
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
export declare const SecretsSchema: z.ZodObject<{
|
|
6
|
+
recoveryKey: z.ZodOptional<z.ZodString>;
|
|
7
|
+
activeApiKey: z.ZodOptional<z.ZodString>;
|
|
8
|
+
activeKeyId: z.ZodOptional<z.ZodString>;
|
|
9
|
+
accessToken: z.ZodOptional<z.ZodString>;
|
|
10
|
+
accessTokenExpiresAt: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
recoveryKey?: string | undefined;
|
|
13
|
+
activeApiKey?: string | undefined;
|
|
14
|
+
activeKeyId?: string | undefined;
|
|
15
|
+
accessToken?: string | undefined;
|
|
16
|
+
accessTokenExpiresAt?: string | undefined;
|
|
17
|
+
}, {
|
|
18
|
+
recoveryKey?: string | undefined;
|
|
19
|
+
activeApiKey?: string | undefined;
|
|
20
|
+
activeKeyId?: string | undefined;
|
|
21
|
+
accessToken?: string | undefined;
|
|
22
|
+
accessTokenExpiresAt?: string | undefined;
|
|
23
|
+
}>;
|
|
24
|
+
export type Secrets = z.infer<typeof SecretsSchema>;
|
|
25
|
+
/**
|
|
26
|
+
* Redacted version for debug output
|
|
27
|
+
*/
|
|
28
|
+
export declare function redactSecrets(secrets: Secrets): Record<string, string>;
|
|
29
|
+
//# sourceMappingURL=secrets-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets-types.d.ts","sourceRoot":"","sources":["../../../src/core/secrets/secrets-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;EAMxB,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiBtE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret storage types and schema
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
export const SecretsSchema = z.object({
|
|
6
|
+
recoveryKey: z.string().optional(),
|
|
7
|
+
activeApiKey: z.string().optional(),
|
|
8
|
+
activeKeyId: z.string().optional(),
|
|
9
|
+
accessToken: z.string().optional(),
|
|
10
|
+
accessTokenExpiresAt: z.string().datetime().optional(),
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Redacted version for debug output
|
|
14
|
+
*/
|
|
15
|
+
export function redactSecrets(secrets) {
|
|
16
|
+
const redacted = {};
|
|
17
|
+
for (const key of Object.keys(secrets)) {
|
|
18
|
+
const value = secrets[key];
|
|
19
|
+
if (value) {
|
|
20
|
+
if (value.length <= 8) {
|
|
21
|
+
redacted[key] = '***';
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
redacted[key] = value.substring(0, 4) + '...' + value.substring(value.length - 4);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
redacted[key] = '<not set>';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return redacted;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=secrets-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets-types.js","sourceRoot":"","sources":["../../../src/core/secrets/secrets-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACvD,CAAC,CAAC;AAIH;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAE5C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAoB,CAAC,CAAC;QAC5C,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;gBACtB,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACpF,CAAC;QACH,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat database schema and migrations
|
|
3
|
+
*/
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
export declare const CHAT_DB_VERSION = 1;
|
|
6
|
+
/**
|
|
7
|
+
* Run chat database migrations
|
|
8
|
+
*/
|
|
9
|
+
export declare function runChatMigrations(db: Database.Database): void;
|
|
10
|
+
/**
|
|
11
|
+
* Initialize chat database with schema
|
|
12
|
+
*/
|
|
13
|
+
export declare function initializeChatDb(db: Database.Database): void;
|
|
14
|
+
//# sourceMappingURL=chat-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-schema.d.ts","sourceRoot":"","sources":["../../../src/core/sqlite/chat-schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC,eAAO,MAAM,eAAe,IAAI,CAAC;AA2KjC;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAE7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAE5D"}
|