@ekkos/cli 1.3.2 → 1.3.5
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/capture/jsonl-rewriter.d.ts +1 -1
- package/dist/capture/jsonl-rewriter.js +3 -3
- package/dist/capture/transcript-repair.d.ts +2 -2
- package/dist/capture/transcript-repair.js +2 -2
- package/dist/commands/claw.d.ts +13 -0
- package/dist/commands/claw.js +253 -0
- package/dist/commands/dashboard.js +617 -83
- package/dist/commands/doctor.d.ts +3 -3
- package/dist/commands/doctor.js +6 -79
- package/dist/commands/gemini.d.ts +19 -0
- package/dist/commands/gemini.js +193 -0
- package/dist/commands/init.js +2 -25
- package/dist/commands/run.d.ts +0 -1
- package/dist/commands/run.js +147 -241
- package/dist/commands/scan.d.ts +21 -0
- package/dist/commands/scan.js +386 -0
- package/dist/commands/swarm-dashboard.js +156 -28
- package/dist/commands/swarm.d.ts +1 -1
- package/dist/commands/swarm.js +1 -1
- package/dist/commands/test-claude.d.ts +2 -2
- package/dist/commands/test-claude.js +3 -3
- package/dist/deploy/index.d.ts +0 -2
- package/dist/deploy/index.js +0 -2
- package/dist/deploy/settings.d.ts +2 -2
- package/dist/deploy/settings.js +42 -4
- package/dist/deploy/skills.js +1 -2
- package/dist/index.js +79 -19
- package/dist/lib/usage-parser.js +4 -3
- package/dist/utils/proxy-url.d.ts +12 -1
- package/dist/utils/proxy-url.js +16 -1
- package/dist/utils/templates.js +1 -1
- package/package.json +4 -6
- package/templates/CLAUDE.md +49 -107
- package/dist/agent/daemon.d.ts +0 -130
- package/dist/agent/daemon.js +0 -606
- package/dist/agent/health-check.d.ts +0 -35
- package/dist/agent/health-check.js +0 -243
- package/dist/agent/pty-runner.d.ts +0 -53
- package/dist/agent/pty-runner.js +0 -190
- package/dist/commands/agent.d.ts +0 -50
- package/dist/commands/agent.js +0 -544
- package/dist/commands/setup-remote.d.ts +0 -20
- package/dist/commands/setup-remote.js +0 -582
- package/dist/commands/synk.d.ts +0 -7
- package/dist/commands/synk.js +0 -339
- package/dist/synk/api.d.ts +0 -22
- package/dist/synk/api.js +0 -133
- package/dist/synk/auth.d.ts +0 -7
- package/dist/synk/auth.js +0 -30
- package/dist/synk/config.d.ts +0 -18
- package/dist/synk/config.js +0 -37
- package/dist/synk/daemon/control-client.d.ts +0 -11
- package/dist/synk/daemon/control-client.js +0 -101
- package/dist/synk/daemon/control-server.d.ts +0 -24
- package/dist/synk/daemon/control-server.js +0 -91
- package/dist/synk/daemon/run.d.ts +0 -14
- package/dist/synk/daemon/run.js +0 -338
- package/dist/synk/encryption.d.ts +0 -17
- package/dist/synk/encryption.js +0 -133
- package/dist/synk/index.d.ts +0 -13
- package/dist/synk/index.js +0 -36
- package/dist/synk/machine-client.d.ts +0 -42
- package/dist/synk/machine-client.js +0 -218
- package/dist/synk/persistence.d.ts +0 -51
- package/dist/synk/persistence.js +0 -211
- package/dist/synk/qr.d.ts +0 -5
- package/dist/synk/qr.js +0 -33
- package/dist/synk/session-bridge.d.ts +0 -58
- package/dist/synk/session-bridge.js +0 -171
- package/dist/synk/session-client.d.ts +0 -46
- package/dist/synk/session-client.js +0 -240
- package/dist/synk/types.d.ts +0 -574
- package/dist/synk/types.js +0 -74
- package/dist/utils/verify-remote-terminal.d.ts +0 -10
- package/dist/utils/verify-remote-terminal.js +0 -415
- package/templates/README.md +0 -378
- package/templates/claude-plugins/PHASE2_COMPLETION.md +0 -346
- package/templates/claude-plugins/PLUGIN_PROPOSALS.md +0 -1776
- package/templates/claude-plugins/README.md +0 -587
- package/templates/claude-plugins/agents/code-reviewer.json +0 -14
- package/templates/claude-plugins/agents/debug-detective.json +0 -15
- package/templates/claude-plugins/agents/git-companion.json +0 -14
- package/templates/claude-plugins/blog-manager/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/blog-manager/commands/blog.md +0 -691
- package/templates/claude-plugins/golden-loop-monitor/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/golden-loop-monitor/commands/loop-status.md +0 -434
- package/templates/claude-plugins/learning-tracker/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/learning-tracker/commands/my-patterns.md +0 -282
- package/templates/claude-plugins/memory-lens/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/memory-lens/commands/memory-search.md +0 -181
- package/templates/claude-plugins/pattern-coach/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/pattern-coach/commands/forge.md +0 -365
- package/templates/claude-plugins/project-schema-validator/.claude-plugin/plugin.json +0 -8
- package/templates/claude-plugins/project-schema-validator/commands/validate-schema.md +0 -582
- package/templates/commands/continue.md +0 -47
- package/templates/cursor-rules/ekkos-memory.md +0 -127
- package/templates/ekkos-manifest.json +0 -223
- package/templates/helpers/json-parse.cjs +0 -101
- package/templates/plan-template.md +0 -306
- package/templates/shared/hooks-enabled.json +0 -22
- package/templates/shared/session-words.json +0 -45
- package/templates/skills/ekkOS_Deep_Recall/Skill.md +0 -282
- package/templates/skills/ekkOS_Learn/Skill.md +0 -265
- package/templates/skills/ekkOS_Memory_First/Skill.md +0 -206
- package/templates/skills/ekkOS_Plan_Assist/Skill.md +0 -302
- package/templates/skills/ekkOS_Preferences/Skill.md +0 -247
- package/templates/skills/ekkOS_Reflect/Skill.md +0 -257
- package/templates/skills/ekkOS_Safety/Skill.md +0 -265
- package/templates/skills/ekkOS_Schema/Skill.md +0 -251
- package/templates/skills/ekkOS_Summary/Skill.md +0 -257
- package/templates/spec-template.md +0 -159
- package/templates/windsurf-rules/ekkos-memory.md +0 -127
- package/templates/windsurf-skills/README.md +0 -58
- package/templates/windsurf-skills/ekkos-continue/SKILL.md +0 -81
- package/templates/windsurf-skills/ekkos-golden-loop/SKILL.md +0 -225
- package/templates/windsurf-skills/ekkos-insights/SKILL.md +0 -138
- package/templates/windsurf-skills/ekkos-recall/SKILL.md +0 -96
- package/templates/windsurf-skills/ekkos-safety/SKILL.md +0 -89
- package/templates/windsurf-skills/ekkos-vault/SKILL.md +0 -86
package/dist/synk/encryption.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.encodeBase64 = encodeBase64;
|
|
7
|
-
exports.encodeBase64Url = encodeBase64Url;
|
|
8
|
-
exports.decodeBase64 = decodeBase64;
|
|
9
|
-
exports.getRandomBytes = getRandomBytes;
|
|
10
|
-
exports.libsodiumPublicKeyFromSecretKey = libsodiumPublicKeyFromSecretKey;
|
|
11
|
-
exports.libsodiumEncryptForPublicKey = libsodiumEncryptForPublicKey;
|
|
12
|
-
exports.encryptLegacy = encryptLegacy;
|
|
13
|
-
exports.decryptLegacy = decryptLegacy;
|
|
14
|
-
exports.encryptWithDataKey = encryptWithDataKey;
|
|
15
|
-
exports.decryptWithDataKey = decryptWithDataKey;
|
|
16
|
-
exports.encrypt = encrypt;
|
|
17
|
-
exports.decrypt = decrypt;
|
|
18
|
-
exports.authChallenge = authChallenge;
|
|
19
|
-
const node_crypto_1 = require("node:crypto");
|
|
20
|
-
const tweetnacl_1 = __importDefault(require("tweetnacl"));
|
|
21
|
-
function encodeBase64(buffer, variant = 'base64') {
|
|
22
|
-
if (variant === 'base64url') {
|
|
23
|
-
return encodeBase64Url(buffer);
|
|
24
|
-
}
|
|
25
|
-
return Buffer.from(buffer).toString('base64');
|
|
26
|
-
}
|
|
27
|
-
function encodeBase64Url(buffer) {
|
|
28
|
-
return Buffer.from(buffer)
|
|
29
|
-
.toString('base64')
|
|
30
|
-
.replace(/\+/g, '-')
|
|
31
|
-
.replace(/\//g, '_')
|
|
32
|
-
.replace(/=/g, '');
|
|
33
|
-
}
|
|
34
|
-
function decodeBase64(base64, variant = 'base64') {
|
|
35
|
-
if (variant === 'base64url') {
|
|
36
|
-
const base64Standard = base64
|
|
37
|
-
.replace(/-/g, '+')
|
|
38
|
-
.replace(/_/g, '/')
|
|
39
|
-
+ '='.repeat((4 - base64.length % 4) % 4);
|
|
40
|
-
return new Uint8Array(Buffer.from(base64Standard, 'base64'));
|
|
41
|
-
}
|
|
42
|
-
return new Uint8Array(Buffer.from(base64, 'base64'));
|
|
43
|
-
}
|
|
44
|
-
function getRandomBytes(size) {
|
|
45
|
-
return new Uint8Array((0, node_crypto_1.randomBytes)(size));
|
|
46
|
-
}
|
|
47
|
-
function libsodiumPublicKeyFromSecretKey(seed) {
|
|
48
|
-
const hashedSeed = new Uint8Array((0, node_crypto_1.createHash)('sha512').update(seed).digest());
|
|
49
|
-
const secretKey = hashedSeed.slice(0, 32);
|
|
50
|
-
return new Uint8Array(tweetnacl_1.default.box.keyPair.fromSecretKey(secretKey).publicKey);
|
|
51
|
-
}
|
|
52
|
-
function libsodiumEncryptForPublicKey(data, recipientPublicKey) {
|
|
53
|
-
const ephemeralKeyPair = tweetnacl_1.default.box.keyPair();
|
|
54
|
-
const nonce = getRandomBytes(tweetnacl_1.default.box.nonceLength);
|
|
55
|
-
const encrypted = tweetnacl_1.default.box(data, nonce, recipientPublicKey, ephemeralKeyPair.secretKey);
|
|
56
|
-
const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
|
|
57
|
-
result.set(ephemeralKeyPair.publicKey, 0);
|
|
58
|
-
result.set(nonce, ephemeralKeyPair.publicKey.length);
|
|
59
|
-
result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
|
|
60
|
-
return result;
|
|
61
|
-
}
|
|
62
|
-
function encryptLegacy(data, secret) {
|
|
63
|
-
const nonce = getRandomBytes(tweetnacl_1.default.secretbox.nonceLength);
|
|
64
|
-
const encrypted = tweetnacl_1.default.secretbox(new TextEncoder().encode(JSON.stringify(data)), nonce, secret);
|
|
65
|
-
const result = new Uint8Array(nonce.length + encrypted.length);
|
|
66
|
-
result.set(nonce);
|
|
67
|
-
result.set(encrypted, nonce.length);
|
|
68
|
-
return result;
|
|
69
|
-
}
|
|
70
|
-
function decryptLegacy(data, secret) {
|
|
71
|
-
const nonce = data.slice(0, tweetnacl_1.default.secretbox.nonceLength);
|
|
72
|
-
const encrypted = data.slice(tweetnacl_1.default.secretbox.nonceLength);
|
|
73
|
-
const decrypted = tweetnacl_1.default.secretbox.open(encrypted, nonce, secret);
|
|
74
|
-
if (!decrypted) {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
return JSON.parse(new TextDecoder().decode(decrypted));
|
|
78
|
-
}
|
|
79
|
-
function encryptWithDataKey(data, dataKey) {
|
|
80
|
-
const nonce = getRandomBytes(12);
|
|
81
|
-
const cipher = (0, node_crypto_1.createCipheriv)('aes-256-gcm', dataKey, nonce);
|
|
82
|
-
const plaintext = new TextEncoder().encode(JSON.stringify(data));
|
|
83
|
-
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
84
|
-
const authTag = cipher.getAuthTag();
|
|
85
|
-
const bundle = new Uint8Array(12 + encrypted.length + 16 + 1);
|
|
86
|
-
bundle.set([0], 0);
|
|
87
|
-
bundle.set(nonce, 1);
|
|
88
|
-
bundle.set(new Uint8Array(encrypted), 13);
|
|
89
|
-
bundle.set(new Uint8Array(authTag), 13 + encrypted.length);
|
|
90
|
-
return bundle;
|
|
91
|
-
}
|
|
92
|
-
function decryptWithDataKey(bundle, dataKey) {
|
|
93
|
-
if (bundle.length < 1)
|
|
94
|
-
return null;
|
|
95
|
-
if (bundle[0] !== 0)
|
|
96
|
-
return null;
|
|
97
|
-
if (bundle.length < 12 + 16 + 1)
|
|
98
|
-
return null;
|
|
99
|
-
const nonce = bundle.slice(1, 13);
|
|
100
|
-
const authTag = bundle.slice(bundle.length - 16);
|
|
101
|
-
const ciphertext = bundle.slice(13, bundle.length - 16);
|
|
102
|
-
try {
|
|
103
|
-
const decipher = (0, node_crypto_1.createDecipheriv)('aes-256-gcm', dataKey, nonce);
|
|
104
|
-
decipher.setAuthTag(authTag);
|
|
105
|
-
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
106
|
-
return JSON.parse(new TextDecoder().decode(decrypted));
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
function encrypt(key, variant, data) {
|
|
113
|
-
if (variant === 'legacy') {
|
|
114
|
-
return encryptLegacy(data, key);
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
return encryptWithDataKey(data, key);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
function decrypt(key, variant, data) {
|
|
121
|
-
if (variant === 'legacy') {
|
|
122
|
-
return decryptLegacy(data, key);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
return decryptWithDataKey(data, key);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
function authChallenge(secret) {
|
|
129
|
-
const keypair = tweetnacl_1.default.sign.keyPair.fromSeed(secret);
|
|
130
|
-
const challenge = getRandomBytes(32);
|
|
131
|
-
const signature = tweetnacl_1.default.sign.detached(challenge, keypair.secretKey);
|
|
132
|
-
return { challenge, publicKey: keypair.publicKey, signature };
|
|
133
|
-
}
|
package/dist/synk/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ekkOS_synk — Remote session sync for Claude Code
|
|
3
|
-
*/
|
|
4
|
-
export { synkConfig } from './config';
|
|
5
|
-
export * from './encryption';
|
|
6
|
-
export * from './auth';
|
|
7
|
-
export * from './persistence';
|
|
8
|
-
export * from './types';
|
|
9
|
-
export { displayQRCode } from './qr';
|
|
10
|
-
export { ApiClient } from './api';
|
|
11
|
-
export { SessionClient } from './session-client';
|
|
12
|
-
export { MachineClient } from './machine-client';
|
|
13
|
-
export { SynkSessionBridge } from './session-bridge';
|
package/dist/synk/index.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* ekkOS_synk — Remote session sync for Claude Code
|
|
4
|
-
*/
|
|
5
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
-
}
|
|
11
|
-
Object.defineProperty(o, k2, desc);
|
|
12
|
-
}) : (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
o[k2] = m[k];
|
|
15
|
-
}));
|
|
16
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
-
};
|
|
19
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.SynkSessionBridge = exports.MachineClient = exports.SessionClient = exports.ApiClient = exports.displayQRCode = exports.synkConfig = void 0;
|
|
21
|
-
var config_1 = require("./config");
|
|
22
|
-
Object.defineProperty(exports, "synkConfig", { enumerable: true, get: function () { return config_1.synkConfig; } });
|
|
23
|
-
__exportStar(require("./encryption"), exports);
|
|
24
|
-
__exportStar(require("./auth"), exports);
|
|
25
|
-
__exportStar(require("./persistence"), exports);
|
|
26
|
-
__exportStar(require("./types"), exports);
|
|
27
|
-
var qr_1 = require("./qr");
|
|
28
|
-
Object.defineProperty(exports, "displayQRCode", { enumerable: true, get: function () { return qr_1.displayQRCode; } });
|
|
29
|
-
var api_1 = require("./api");
|
|
30
|
-
Object.defineProperty(exports, "ApiClient", { enumerable: true, get: function () { return api_1.ApiClient; } });
|
|
31
|
-
var session_client_1 = require("./session-client");
|
|
32
|
-
Object.defineProperty(exports, "SessionClient", { enumerable: true, get: function () { return session_client_1.SessionClient; } });
|
|
33
|
-
var machine_client_1 = require("./machine-client");
|
|
34
|
-
Object.defineProperty(exports, "MachineClient", { enumerable: true, get: function () { return machine_client_1.MachineClient; } });
|
|
35
|
-
var session_bridge_1 = require("./session-bridge");
|
|
36
|
-
Object.defineProperty(exports, "SynkSessionBridge", { enumerable: true, get: function () { return session_bridge_1.SynkSessionBridge; } });
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WebSocket client for machine/daemon communication with synk-server
|
|
3
|
-
* Manages keep-alive heartbeat, daemon state updates, and RPC handler registration
|
|
4
|
-
*
|
|
5
|
-
* This is SEPARATE from SessionClient — SessionClient is per-session, MachineClient is per-daemon.
|
|
6
|
-
*/
|
|
7
|
-
import type { MachineMetadata, DaemonState, Machine } from './types';
|
|
8
|
-
export interface SpawnSessionOptions {
|
|
9
|
-
machineId?: string;
|
|
10
|
-
directory: string;
|
|
11
|
-
sessionId?: string;
|
|
12
|
-
environmentVariables?: Record<string, string>;
|
|
13
|
-
}
|
|
14
|
-
export type SpawnSessionResult = {
|
|
15
|
-
type: 'success';
|
|
16
|
-
sessionId: string;
|
|
17
|
-
} | {
|
|
18
|
-
type: 'error';
|
|
19
|
-
errorMessage: string;
|
|
20
|
-
};
|
|
21
|
-
interface MachineRpcHandlers {
|
|
22
|
-
spawnSession: (options: SpawnSessionOptions) => Promise<SpawnSessionResult>;
|
|
23
|
-
stopSession: (sessionId: string) => boolean;
|
|
24
|
-
requestShutdown: () => void;
|
|
25
|
-
}
|
|
26
|
-
export declare class MachineClient {
|
|
27
|
-
private readonly token;
|
|
28
|
-
private readonly machine;
|
|
29
|
-
private socket;
|
|
30
|
-
private keepAliveInterval;
|
|
31
|
-
private rpcHandlerManager;
|
|
32
|
-
private log;
|
|
33
|
-
constructor(token: string, machine: Machine, logger?: (msg: string, ...args: any[]) => void);
|
|
34
|
-
setRPCHandlers({ spawnSession, stopSession, requestShutdown }: MachineRpcHandlers): void;
|
|
35
|
-
updateMachineMetadata(handler: (metadata: MachineMetadata | null) => MachineMetadata): Promise<void>;
|
|
36
|
-
updateDaemonState(handler: (state: DaemonState | null) => DaemonState): Promise<void>;
|
|
37
|
-
connect(): void;
|
|
38
|
-
private startKeepAlive;
|
|
39
|
-
private stopKeepAlive;
|
|
40
|
-
shutdown(): void;
|
|
41
|
-
}
|
|
42
|
-
export {};
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* WebSocket client for machine/daemon communication with synk-server
|
|
4
|
-
* Manages keep-alive heartbeat, daemon state updates, and RPC handler registration
|
|
5
|
-
*
|
|
6
|
-
* This is SEPARATE from SessionClient — SessionClient is per-session, MachineClient is per-daemon.
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.MachineClient = void 0;
|
|
10
|
-
const socket_io_client_1 = require("socket.io-client");
|
|
11
|
-
const config_1 = require("./config");
|
|
12
|
-
const encryption_1 = require("./encryption");
|
|
13
|
-
class RpcHandlerManager {
|
|
14
|
-
constructor(scopePrefix, encryptionKey, encryptionVariant, log) {
|
|
15
|
-
this.scopePrefix = scopePrefix;
|
|
16
|
-
this.encryptionKey = encryptionKey;
|
|
17
|
-
this.encryptionVariant = encryptionVariant;
|
|
18
|
-
this.log = log;
|
|
19
|
-
this.handlers = new Map();
|
|
20
|
-
this.socket = null;
|
|
21
|
-
}
|
|
22
|
-
registerHandler(method, handler) {
|
|
23
|
-
const prefixed = `${this.scopePrefix}:${method}`;
|
|
24
|
-
this.handlers.set(prefixed, handler);
|
|
25
|
-
if (this.socket) {
|
|
26
|
-
this.socket.emit('rpc-register', { method: prefixed });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
async handleRequest(request) {
|
|
30
|
-
try {
|
|
31
|
-
const handler = this.handlers.get(request.method);
|
|
32
|
-
if (!handler) {
|
|
33
|
-
this.log('[RPC] Method not found:', request.method);
|
|
34
|
-
return (0, encryption_1.encodeBase64)((0, encryption_1.encrypt)(this.encryptionKey, this.encryptionVariant, { error: 'Method not found' }));
|
|
35
|
-
}
|
|
36
|
-
const params = (0, encryption_1.decrypt)(this.encryptionKey, this.encryptionVariant, (0, encryption_1.decodeBase64)(request.params));
|
|
37
|
-
this.log('[RPC] Calling handler:', request.method);
|
|
38
|
-
const result = await handler(params);
|
|
39
|
-
return (0, encryption_1.encodeBase64)((0, encryption_1.encrypt)(this.encryptionKey, this.encryptionVariant, result));
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
this.log('[RPC] Error:', error);
|
|
43
|
-
return (0, encryption_1.encodeBase64)((0, encryption_1.encrypt)(this.encryptionKey, this.encryptionVariant, {
|
|
44
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
45
|
-
}));
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
onSocketConnect(socket) {
|
|
49
|
-
this.socket = socket;
|
|
50
|
-
for (const [method] of this.handlers) {
|
|
51
|
-
socket.emit('rpc-register', { method });
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
onSocketDisconnect() {
|
|
55
|
-
this.socket = null;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// --- MachineClient ---
|
|
59
|
-
class MachineClient {
|
|
60
|
-
constructor(token, machine, logger) {
|
|
61
|
-
this.token = token;
|
|
62
|
-
this.machine = machine;
|
|
63
|
-
this.keepAliveInterval = null;
|
|
64
|
-
this.log = logger || ((...args) => console.log('[MACHINE]', ...args));
|
|
65
|
-
this.rpcHandlerManager = new RpcHandlerManager(this.machine.id, this.machine.encryptionKey, this.machine.encryptionVariant, this.log);
|
|
66
|
-
}
|
|
67
|
-
setRPCHandlers({ spawnSession, stopSession, requestShutdown }) {
|
|
68
|
-
this.rpcHandlerManager.registerHandler('spawn-synk-session', async (params) => {
|
|
69
|
-
const { directory, sessionId, machineId, environmentVariables } = params || {};
|
|
70
|
-
this.log('Spawning session:', JSON.stringify(params));
|
|
71
|
-
if (!directory) {
|
|
72
|
-
throw new Error('Directory is required');
|
|
73
|
-
}
|
|
74
|
-
const result = await spawnSession({ directory, sessionId, machineId, environmentVariables });
|
|
75
|
-
switch (result.type) {
|
|
76
|
-
case 'success':
|
|
77
|
-
this.log('Spawned session:', result.sessionId);
|
|
78
|
-
return { type: 'success', sessionId: result.sessionId };
|
|
79
|
-
case 'error':
|
|
80
|
-
throw new Error(result.errorMessage);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
this.rpcHandlerManager.registerHandler('stop-session', (params) => {
|
|
84
|
-
const { sessionId } = params || {};
|
|
85
|
-
if (!sessionId)
|
|
86
|
-
throw new Error('Session ID is required');
|
|
87
|
-
const success = stopSession(sessionId);
|
|
88
|
-
if (!success)
|
|
89
|
-
throw new Error('Session not found or failed to stop');
|
|
90
|
-
this.log('Stopped session:', sessionId);
|
|
91
|
-
return { message: 'Session stopped' };
|
|
92
|
-
});
|
|
93
|
-
this.rpcHandlerManager.registerHandler('stop-daemon', () => {
|
|
94
|
-
this.log('Received stop-daemon RPC');
|
|
95
|
-
setTimeout(() => requestShutdown(), 100);
|
|
96
|
-
return { message: 'Daemon shutdown initiated' };
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
async updateMachineMetadata(handler) {
|
|
100
|
-
const maxRetries = 3;
|
|
101
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
102
|
-
const updated = handler(this.machine.metadata);
|
|
103
|
-
const answer = await this.socket.emitWithAck('machine-update-metadata', {
|
|
104
|
-
machineId: this.machine.id,
|
|
105
|
-
metadata: (0, encryption_1.encodeBase64)((0, encryption_1.encrypt)(this.machine.encryptionKey, this.machine.encryptionVariant, updated)),
|
|
106
|
-
expectedVersion: this.machine.metadataVersion,
|
|
107
|
-
});
|
|
108
|
-
if (answer.result === 'success') {
|
|
109
|
-
this.machine.metadata = (0, encryption_1.decrypt)(this.machine.encryptionKey, this.machine.encryptionVariant, (0, encryption_1.decodeBase64)(answer.metadata));
|
|
110
|
-
this.machine.metadataVersion = answer.version;
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (answer.result === 'version-mismatch' && answer.version > this.machine.metadataVersion) {
|
|
114
|
-
this.machine.metadataVersion = answer.version;
|
|
115
|
-
this.machine.metadata = (0, encryption_1.decrypt)(this.machine.encryptionKey, this.machine.encryptionVariant, (0, encryption_1.decodeBase64)(answer.metadata));
|
|
116
|
-
}
|
|
117
|
-
if (attempt < maxRetries - 1) {
|
|
118
|
-
await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
async updateDaemonState(handler) {
|
|
123
|
-
const maxRetries = 3;
|
|
124
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
125
|
-
const updated = handler(this.machine.daemonState);
|
|
126
|
-
const answer = await this.socket.emitWithAck('machine-update-state', {
|
|
127
|
-
machineId: this.machine.id,
|
|
128
|
-
daemonState: (0, encryption_1.encodeBase64)((0, encryption_1.encrypt)(this.machine.encryptionKey, this.machine.encryptionVariant, updated)),
|
|
129
|
-
expectedVersion: this.machine.daemonStateVersion,
|
|
130
|
-
});
|
|
131
|
-
if (answer.result === 'success') {
|
|
132
|
-
this.machine.daemonState = (0, encryption_1.decrypt)(this.machine.encryptionKey, this.machine.encryptionVariant, (0, encryption_1.decodeBase64)(answer.daemonState));
|
|
133
|
-
this.machine.daemonStateVersion = answer.version;
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (answer.result === 'version-mismatch' && answer.version > this.machine.daemonStateVersion) {
|
|
137
|
-
this.machine.daemonStateVersion = answer.version;
|
|
138
|
-
this.machine.daemonState = (0, encryption_1.decrypt)(this.machine.encryptionKey, this.machine.encryptionVariant, (0, encryption_1.decodeBase64)(answer.daemonState));
|
|
139
|
-
}
|
|
140
|
-
if (attempt < maxRetries - 1) {
|
|
141
|
-
await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
connect() {
|
|
146
|
-
this.log('Connecting to', config_1.synkConfig.serverUrl);
|
|
147
|
-
this.socket = (0, socket_io_client_1.io)(config_1.synkConfig.serverUrl, {
|
|
148
|
-
transports: ['websocket'],
|
|
149
|
-
auth: {
|
|
150
|
-
token: this.token,
|
|
151
|
-
clientType: 'machine-scoped',
|
|
152
|
-
machineId: this.machine.id,
|
|
153
|
-
},
|
|
154
|
-
path: '/v1/updates',
|
|
155
|
-
reconnection: true,
|
|
156
|
-
reconnectionDelay: 1000,
|
|
157
|
-
reconnectionDelayMax: 5000,
|
|
158
|
-
});
|
|
159
|
-
this.socket.on('connect', () => {
|
|
160
|
-
this.log('Connected to synk-server');
|
|
161
|
-
this.updateDaemonState((state) => ({
|
|
162
|
-
...state,
|
|
163
|
-
status: 'running',
|
|
164
|
-
pid: process.pid,
|
|
165
|
-
httpPort: this.machine.daemonState?.httpPort,
|
|
166
|
-
startedAt: Date.now(),
|
|
167
|
-
})).catch(err => this.log('Failed to update daemon state:', err));
|
|
168
|
-
this.rpcHandlerManager.onSocketConnect(this.socket);
|
|
169
|
-
this.startKeepAlive();
|
|
170
|
-
});
|
|
171
|
-
this.socket.on('disconnect', () => {
|
|
172
|
-
this.log('Disconnected from synk-server');
|
|
173
|
-
this.rpcHandlerManager.onSocketDisconnect();
|
|
174
|
-
this.stopKeepAlive();
|
|
175
|
-
});
|
|
176
|
-
this.socket.on('rpc-request', async (data, callback) => {
|
|
177
|
-
callback(await this.rpcHandlerManager.handleRequest(data));
|
|
178
|
-
});
|
|
179
|
-
this.socket.on('update', (data) => {
|
|
180
|
-
if (data.body?.t === 'update-machine' && data.body.machineId === this.machine.id) {
|
|
181
|
-
if (data.body.metadata) {
|
|
182
|
-
this.machine.metadata = (0, encryption_1.decrypt)(this.machine.encryptionKey, this.machine.encryptionVariant, (0, encryption_1.decodeBase64)(data.body.metadata.value));
|
|
183
|
-
this.machine.metadataVersion = data.body.metadata.version;
|
|
184
|
-
}
|
|
185
|
-
if (data.body.daemonState) {
|
|
186
|
-
this.machine.daemonState = (0, encryption_1.decrypt)(this.machine.encryptionKey, this.machine.encryptionVariant, (0, encryption_1.decodeBase64)(data.body.daemonState.value));
|
|
187
|
-
this.machine.daemonStateVersion = data.body.daemonState.version;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
this.socket.on('connect_error', (error) => {
|
|
192
|
-
this.log('Connection error:', error.message);
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
startKeepAlive() {
|
|
196
|
-
this.stopKeepAlive();
|
|
197
|
-
this.keepAliveInterval = setInterval(() => {
|
|
198
|
-
this.socket.emit('machine-alive', {
|
|
199
|
-
machineId: this.machine.id,
|
|
200
|
-
time: Date.now(),
|
|
201
|
-
});
|
|
202
|
-
}, 20000);
|
|
203
|
-
}
|
|
204
|
-
stopKeepAlive() {
|
|
205
|
-
if (this.keepAliveInterval) {
|
|
206
|
-
clearInterval(this.keepAliveInterval);
|
|
207
|
-
this.keepAliveInterval = null;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
shutdown() {
|
|
211
|
-
this.log('Shutting down');
|
|
212
|
-
this.stopKeepAlive();
|
|
213
|
-
if (this.socket) {
|
|
214
|
-
this.socket.close();
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
exports.MachineClient = MachineClient;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistence for ekkOS_synk — credentials, settings, daemon state
|
|
3
|
-
*/
|
|
4
|
-
import { FileHandle } from 'node:fs/promises';
|
|
5
|
-
/** Daemon state persisted locally */
|
|
6
|
-
export interface DaemonLocallyPersistedState {
|
|
7
|
-
pid: number;
|
|
8
|
-
httpPort: number;
|
|
9
|
-
startTime: string;
|
|
10
|
-
startedWithCliVersion: string;
|
|
11
|
-
lastHeartbeat?: string;
|
|
12
|
-
daemonLogPath?: string;
|
|
13
|
-
}
|
|
14
|
-
interface Settings {
|
|
15
|
-
schemaVersion: number;
|
|
16
|
-
onboardingCompleted: boolean;
|
|
17
|
-
machineId?: string;
|
|
18
|
-
machineIdConfirmedByServer?: boolean;
|
|
19
|
-
daemonAutoStart?: boolean;
|
|
20
|
-
}
|
|
21
|
-
export type Credentials = {
|
|
22
|
-
token: string;
|
|
23
|
-
encryption: {
|
|
24
|
-
type: 'legacy';
|
|
25
|
-
secret: Uint8Array;
|
|
26
|
-
} | {
|
|
27
|
-
type: 'dataKey';
|
|
28
|
-
publicKey: Uint8Array;
|
|
29
|
-
machineKey: Uint8Array;
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
export declare function readCredentials(): Promise<Credentials | null>;
|
|
33
|
-
export declare function writeCredentialsLegacy(credentials: {
|
|
34
|
-
secret: Uint8Array;
|
|
35
|
-
token: string;
|
|
36
|
-
}): Promise<void>;
|
|
37
|
-
export declare function writeCredentialsDataKey(credentials: {
|
|
38
|
-
publicKey: Uint8Array;
|
|
39
|
-
machineKey: Uint8Array;
|
|
40
|
-
token: string;
|
|
41
|
-
}): Promise<void>;
|
|
42
|
-
export declare function clearCredentials(): Promise<void>;
|
|
43
|
-
export declare function readSettings(): Promise<Settings>;
|
|
44
|
-
export declare function writeSettings(settings: Settings): Promise<void>;
|
|
45
|
-
export declare function updateSettings(updater: (current: Settings) => Settings | Promise<Settings>): Promise<Settings>;
|
|
46
|
-
export declare function readDaemonState(): Promise<DaemonLocallyPersistedState | null>;
|
|
47
|
-
export declare function writeDaemonState(state: DaemonLocallyPersistedState): void;
|
|
48
|
-
export declare function clearDaemonState(): Promise<void>;
|
|
49
|
-
export declare function acquireDaemonLock(maxAttempts?: number, delayIncrementMs?: number): Promise<FileHandle | null>;
|
|
50
|
-
export declare function releaseDaemonLock(lockHandle: FileHandle): Promise<void>;
|
|
51
|
-
export {};
|