@ekkos/cli 1.3.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/commands/dashboard.js +147 -57
  2. package/dist/commands/init.d.ts +1 -0
  3. package/dist/commands/init.js +54 -16
  4. package/dist/commands/run.js +163 -44
  5. package/dist/commands/status.d.ts +4 -1
  6. package/dist/commands/status.js +165 -27
  7. package/dist/commands/synk.d.ts +7 -0
  8. package/dist/commands/synk.js +339 -0
  9. package/dist/deploy/settings.d.ts +6 -5
  10. package/dist/deploy/settings.js +27 -17
  11. package/dist/index.js +12 -82
  12. package/dist/lib/usage-parser.d.ts +1 -1
  13. package/dist/lib/usage-parser.js +5 -3
  14. package/dist/local/index.d.ts +14 -0
  15. package/dist/local/index.js +28 -0
  16. package/dist/local/local-embeddings.d.ts +49 -0
  17. package/dist/local/local-embeddings.js +232 -0
  18. package/dist/local/offline-fallback.d.ts +44 -0
  19. package/dist/local/offline-fallback.js +159 -0
  20. package/dist/local/sqlite-store.d.ts +126 -0
  21. package/dist/local/sqlite-store.js +393 -0
  22. package/dist/local/sync-engine.d.ts +42 -0
  23. package/dist/local/sync-engine.js +223 -0
  24. package/dist/synk/api.d.ts +22 -0
  25. package/dist/synk/api.js +133 -0
  26. package/dist/synk/auth.d.ts +7 -0
  27. package/dist/synk/auth.js +30 -0
  28. package/dist/synk/config.d.ts +18 -0
  29. package/dist/synk/config.js +37 -0
  30. package/dist/synk/daemon/control-client.d.ts +11 -0
  31. package/dist/synk/daemon/control-client.js +101 -0
  32. package/dist/synk/daemon/control-server.d.ts +24 -0
  33. package/dist/synk/daemon/control-server.js +91 -0
  34. package/dist/synk/daemon/run.d.ts +14 -0
  35. package/dist/synk/daemon/run.js +338 -0
  36. package/dist/synk/encryption.d.ts +17 -0
  37. package/dist/synk/encryption.js +133 -0
  38. package/dist/synk/index.d.ts +13 -0
  39. package/dist/synk/index.js +36 -0
  40. package/dist/synk/machine-client.d.ts +42 -0
  41. package/dist/synk/machine-client.js +218 -0
  42. package/dist/synk/persistence.d.ts +51 -0
  43. package/dist/synk/persistence.js +211 -0
  44. package/dist/synk/qr.d.ts +5 -0
  45. package/dist/synk/qr.js +33 -0
  46. package/dist/synk/session-bridge.d.ts +58 -0
  47. package/dist/synk/session-bridge.js +171 -0
  48. package/dist/synk/session-client.d.ts +46 -0
  49. package/dist/synk/session-client.js +240 -0
  50. package/dist/synk/types.d.ts +574 -0
  51. package/dist/synk/types.js +74 -0
  52. package/dist/utils/platform.d.ts +5 -1
  53. package/dist/utils/platform.js +24 -4
  54. package/dist/utils/proxy-url.d.ts +10 -0
  55. package/dist/utils/proxy-url.js +19 -0
  56. package/dist/utils/state.d.ts +1 -1
  57. package/dist/utils/state.js +11 -3
  58. package/package.json +13 -4
  59. package/templates/claude-plugins-admin/AGENT_TEAM_PROPOSALS.md +0 -819
  60. package/templates/claude-plugins-admin/README.md +0 -446
  61. package/templates/claude-plugins-admin/autonomous-admin-agent/.claude-plugin/plugin.json +0 -8
  62. package/templates/claude-plugins-admin/autonomous-admin-agent/commands/agent.md +0 -595
  63. package/templates/claude-plugins-admin/backend-agent/.claude-plugin/plugin.json +0 -8
  64. package/templates/claude-plugins-admin/backend-agent/commands/backend.md +0 -798
  65. package/templates/claude-plugins-admin/deploy-guardian/.claude-plugin/plugin.json +0 -8
  66. package/templates/claude-plugins-admin/deploy-guardian/commands/deploy.md +0 -554
  67. package/templates/claude-plugins-admin/frontend-agent/.claude-plugin/plugin.json +0 -8
  68. package/templates/claude-plugins-admin/frontend-agent/commands/frontend.md +0 -881
  69. package/templates/claude-plugins-admin/mcp-server-manager/.claude-plugin/plugin.json +0 -8
  70. package/templates/claude-plugins-admin/mcp-server-manager/commands/mcp.md +0 -85
  71. package/templates/claude-plugins-admin/memory-system-monitor/.claude-plugin/plugin.json +0 -8
  72. package/templates/claude-plugins-admin/memory-system-monitor/commands/memory-health.md +0 -569
  73. package/templates/claude-plugins-admin/qa-agent/.claude-plugin/plugin.json +0 -8
  74. package/templates/claude-plugins-admin/qa-agent/commands/qa.md +0 -863
  75. package/templates/claude-plugins-admin/tech-lead-agent/.claude-plugin/plugin.json +0 -8
  76. package/templates/claude-plugins-admin/tech-lead-agent/commands/lead.md +0 -732
  77. package/templates/hooks-node/lib/state.js +0 -187
  78. package/templates/hooks-node/stop.js +0 -416
  79. package/templates/hooks-node/user-prompt-submit.js +0 -337
  80. package/templates/rules/00-hooks-contract.mdc +0 -89
  81. package/templates/rules/30-ekkos-core.mdc +0 -188
  82. package/templates/rules/31-ekkos-messages.mdc +0 -78
@@ -0,0 +1,339 @@
1
+ "use strict";
2
+ /**
3
+ * ekkOS_synk commands — remote session sync for Claude Code
4
+ *
5
+ * Provides: ekkos synk auth, connect, disconnect, sessions, daemon start/stop/status, doctor
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.registerSynkCommands = registerSynkCommands;
45
+ const chalk_1 = __importDefault(require("chalk"));
46
+ function registerSynkCommands(program) {
47
+ const synkCmd = program
48
+ .command('synk')
49
+ .description('Remote session sync — control Claude Code from anywhere');
50
+ // ── Auth ──
51
+ synkCmd
52
+ .command('auth')
53
+ .description('Authenticate with synk-server and display QR code for mobile pairing')
54
+ .option('-f, --force', 'Force re-authentication')
55
+ .action(async (options) => {
56
+ const { synkConfig } = await Promise.resolve().then(() => __importStar(require('../synk/config')));
57
+ const { readCredentials } = await Promise.resolve().then(() => __importStar(require('../synk/persistence')));
58
+ const { getRandomBytes, encodeBase64 } = await Promise.resolve().then(() => __importStar(require('../synk/encryption')));
59
+ const { authGetToken, generateAppUrl } = await Promise.resolve().then(() => __importStar(require('../synk/auth')));
60
+ const { displayQRCode } = await Promise.resolve().then(() => __importStar(require('../synk/qr')));
61
+ synkConfig.ensureDirectories();
62
+ let credentials = await readCredentials();
63
+ if (credentials && !options.force) {
64
+ console.log(chalk_1.default.green(' Already authenticated with synk-server.'));
65
+ console.log(chalk_1.default.gray(` Server: ${synkConfig.serverUrl}`));
66
+ console.log(chalk_1.default.gray(` Use --force to re-authenticate.`));
67
+ // Still show QR code for mobile pairing
68
+ if (credentials.encryption.type === 'legacy') {
69
+ const url = generateAppUrl(credentials.encryption.secret);
70
+ displayQRCode(url);
71
+ }
72
+ return;
73
+ }
74
+ console.log('');
75
+ console.log(chalk_1.default.cyan.bold(' ekkOS_synk') + chalk_1.default.gray(' — Setting up remote session sync'));
76
+ console.log('');
77
+ // Generate new secret key
78
+ const secret = getRandomBytes(32);
79
+ try {
80
+ const token = await authGetToken(secret);
81
+ const { writeCredentialsLegacy } = await Promise.resolve().then(() => __importStar(require('../synk/persistence')));
82
+ await writeCredentialsLegacy({ secret, token });
83
+ console.log(chalk_1.default.green(' Authenticated successfully!'));
84
+ console.log(chalk_1.default.gray(` Server: ${synkConfig.serverUrl}`));
85
+ console.log(chalk_1.default.gray(` Credentials saved to: ${synkConfig.credentialsFile}`));
86
+ // Show QR code for mobile pairing
87
+ const url = generateAppUrl(secret);
88
+ displayQRCode(url);
89
+ }
90
+ catch (error) {
91
+ console.error(chalk_1.default.red(` Authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`));
92
+ process.exit(1);
93
+ }
94
+ });
95
+ // ── Status (default when running `ekkos synk`) ──
96
+ synkCmd
97
+ .command('status', { isDefault: true })
98
+ .description('Show synk connection status')
99
+ .action(async () => {
100
+ const { synkConfig } = await Promise.resolve().then(() => __importStar(require('../synk/config')));
101
+ const { readCredentials, readDaemonState } = await Promise.resolve().then(() => __importStar(require('../synk/persistence')));
102
+ console.log('');
103
+ console.log(chalk_1.default.cyan.bold(' ekkOS_synk') + chalk_1.default.gray(' — Remote Session Sync'));
104
+ console.log('');
105
+ // Check credentials
106
+ const credentials = await readCredentials();
107
+ if (!credentials) {
108
+ console.log(chalk_1.default.yellow(' Not authenticated.'));
109
+ console.log(chalk_1.default.gray(' Run: ') + chalk_1.default.white('ekkos synk auth'));
110
+ console.log('');
111
+ return;
112
+ }
113
+ console.log(` ${chalk_1.default.green('●')} Authenticated`);
114
+ console.log(chalk_1.default.gray(` Server: ${synkConfig.serverUrl}`));
115
+ // Check daemon
116
+ const daemonState = await readDaemonState();
117
+ if (daemonState) {
118
+ try {
119
+ process.kill(daemonState.pid, 0);
120
+ console.log(` ${chalk_1.default.green('●')} Daemon running`);
121
+ console.log(chalk_1.default.gray(` PID: ${daemonState.pid} | Port: ${daemonState.httpPort}`));
122
+ console.log(chalk_1.default.gray(` Started: ${daemonState.startTime}`));
123
+ if (daemonState.lastHeartbeat) {
124
+ console.log(chalk_1.default.gray(` Last heartbeat: ${daemonState.lastHeartbeat}`));
125
+ }
126
+ }
127
+ catch {
128
+ console.log(` ${chalk_1.default.red('●')} Daemon not running (stale state)`);
129
+ console.log(chalk_1.default.gray(' Run: ') + chalk_1.default.white('ekkos synk daemon start'));
130
+ }
131
+ }
132
+ else {
133
+ console.log(` ${chalk_1.default.gray('○')} Daemon not running`);
134
+ console.log(chalk_1.default.gray(' Run: ') + chalk_1.default.white('ekkos synk daemon start'));
135
+ }
136
+ console.log('');
137
+ });
138
+ // ── Connect ──
139
+ synkCmd
140
+ .command('connect')
141
+ .description('Start daemon and connect to synk-server')
142
+ .action(async () => {
143
+ const { readCredentials } = await Promise.resolve().then(() => __importStar(require('../synk/persistence')));
144
+ const credentials = await readCredentials();
145
+ if (!credentials) {
146
+ console.log(chalk_1.default.yellow(' Not authenticated. Run: ') + chalk_1.default.white('ekkos synk auth'));
147
+ process.exit(1);
148
+ }
149
+ console.log(chalk_1.default.cyan(' Starting synk daemon...'));
150
+ // Spawn daemon in detached mode
151
+ const { spawn } = await Promise.resolve().then(() => __importStar(require('node:child_process')));
152
+ const child = spawn(process.execPath, [process.argv[1], 'synk', 'daemon', 'start-sync'], {
153
+ detached: true,
154
+ stdio: 'ignore',
155
+ });
156
+ child.unref();
157
+ // Wait a moment and check if it started
158
+ await new Promise(resolve => setTimeout(resolve, 1500));
159
+ const { readDaemonState } = await Promise.resolve().then(() => __importStar(require('../synk/persistence')));
160
+ const state = await readDaemonState();
161
+ if (state) {
162
+ console.log(chalk_1.default.green(' Daemon started successfully!'));
163
+ console.log(chalk_1.default.gray(` PID: ${state.pid} | Port: ${state.httpPort}`));
164
+ }
165
+ else {
166
+ console.log(chalk_1.default.yellow(' Daemon may still be starting. Check: ') + chalk_1.default.white('ekkos synk status'));
167
+ }
168
+ });
169
+ // ── Disconnect ──
170
+ synkCmd
171
+ .command('disconnect')
172
+ .description('Stop the synk daemon')
173
+ .action(async () => {
174
+ const { stopDaemon } = await Promise.resolve().then(() => __importStar(require('../synk/daemon/control-client')));
175
+ console.log(chalk_1.default.cyan(' Stopping synk daemon...'));
176
+ await stopDaemon();
177
+ console.log(chalk_1.default.green(' Daemon stopped.'));
178
+ });
179
+ // ── Sessions ──
180
+ synkCmd
181
+ .command('sessions')
182
+ .description('List active synk sessions')
183
+ .option('-j, --json', 'Output as JSON')
184
+ .action(async (options) => {
185
+ const { listDaemonSessions } = await Promise.resolve().then(() => __importStar(require('../synk/daemon/control-client')));
186
+ const sessions = await listDaemonSessions();
187
+ if (options.json) {
188
+ console.log(JSON.stringify(sessions, null, 2));
189
+ return;
190
+ }
191
+ console.log('');
192
+ console.log(chalk_1.default.cyan.bold(' Synk Sessions'));
193
+ console.log('');
194
+ if (sessions.length === 0) {
195
+ console.log(chalk_1.default.gray(' No active sessions.'));
196
+ }
197
+ else {
198
+ for (const session of sessions) {
199
+ console.log(` ${chalk_1.default.green('●')} ${chalk_1.default.bold(session.synkSessionId || 'unknown')}`);
200
+ console.log(chalk_1.default.gray(` PID: ${session.pid} | Started by: ${session.startedBy}`));
201
+ }
202
+ }
203
+ console.log('');
204
+ });
205
+ // ── Daemon subcommand ──
206
+ const daemonCmd = synkCmd
207
+ .command('daemon')
208
+ .description('Manage the synk background daemon');
209
+ daemonCmd
210
+ .command('start')
211
+ .description('Start the synk daemon')
212
+ .option('-v, --verbose', 'Show verbose output')
213
+ .action(async (options) => {
214
+ const { checkIfDaemonRunning } = await Promise.resolve().then(() => __importStar(require('../synk/daemon/control-client')));
215
+ const running = await checkIfDaemonRunning();
216
+ if (running) {
217
+ console.log(chalk_1.default.yellow(' Daemon is already running.'));
218
+ return;
219
+ }
220
+ console.log(chalk_1.default.cyan(' Starting synk daemon...'));
221
+ const { spawn } = await Promise.resolve().then(() => __importStar(require('node:child_process')));
222
+ const child = spawn(process.execPath, [process.argv[1], 'synk', 'daemon', 'start-sync'], {
223
+ detached: true,
224
+ stdio: options.verbose ? 'inherit' : 'ignore',
225
+ });
226
+ child.unref();
227
+ await new Promise(resolve => setTimeout(resolve, 1500));
228
+ const { readDaemonState } = await Promise.resolve().then(() => __importStar(require('../synk/persistence')));
229
+ const state = await readDaemonState();
230
+ if (state) {
231
+ console.log(chalk_1.default.green(' Daemon started.'));
232
+ console.log(chalk_1.default.gray(` PID: ${state.pid} | Port: ${state.httpPort}`));
233
+ }
234
+ else {
235
+ console.log(chalk_1.default.yellow(' Daemon may still be starting...'));
236
+ }
237
+ });
238
+ // Internal: start-sync runs the daemon in the foreground (called by detached process)
239
+ daemonCmd
240
+ .command('start-sync')
241
+ .description('Run daemon in foreground (internal)')
242
+ .action(async () => {
243
+ const { startDaemon } = await Promise.resolve().then(() => __importStar(require('../synk/daemon/run')));
244
+ await startDaemon();
245
+ });
246
+ daemonCmd
247
+ .command('stop')
248
+ .description('Stop the synk daemon')
249
+ .action(async () => {
250
+ const { stopDaemon } = await Promise.resolve().then(() => __importStar(require('../synk/daemon/control-client')));
251
+ console.log(chalk_1.default.cyan(' Stopping synk daemon...'));
252
+ await stopDaemon();
253
+ console.log(chalk_1.default.green(' Daemon stopped.'));
254
+ });
255
+ daemonCmd
256
+ .command('status')
257
+ .description('Show daemon status')
258
+ .option('-j, --json', 'Output as JSON')
259
+ .action(async (options) => {
260
+ const { readDaemonState } = await Promise.resolve().then(() => __importStar(require('../synk/persistence')));
261
+ const state = await readDaemonState();
262
+ if (options.json) {
263
+ console.log(JSON.stringify(state, null, 2));
264
+ return;
265
+ }
266
+ if (!state) {
267
+ console.log(chalk_1.default.gray(' Daemon is not running.'));
268
+ return;
269
+ }
270
+ try {
271
+ process.kill(state.pid, 0);
272
+ console.log(` ${chalk_1.default.green('●')} Daemon running`);
273
+ console.log(chalk_1.default.gray(` PID: ${state.pid}`));
274
+ console.log(chalk_1.default.gray(` Port: ${state.httpPort}`));
275
+ console.log(chalk_1.default.gray(` Started: ${state.startTime}`));
276
+ console.log(chalk_1.default.gray(` Version: ${state.startedWithCliVersion}`));
277
+ if (state.lastHeartbeat) {
278
+ console.log(chalk_1.default.gray(` Last heartbeat: ${state.lastHeartbeat}`));
279
+ }
280
+ if (state.daemonLogPath) {
281
+ console.log(chalk_1.default.gray(` Log: ${state.daemonLogPath}`));
282
+ }
283
+ }
284
+ catch {
285
+ console.log(` ${chalk_1.default.red('●')} Daemon not running (stale state file)`);
286
+ console.log(chalk_1.default.gray(' Cleaning up...'));
287
+ const { clearDaemonState } = await Promise.resolve().then(() => __importStar(require('../synk/persistence')));
288
+ await clearDaemonState();
289
+ console.log(chalk_1.default.gray(' Done.'));
290
+ }
291
+ });
292
+ // ── Doctor ──
293
+ synkCmd
294
+ .command('doctor')
295
+ .description('Diagnose synk connectivity and configuration')
296
+ .action(async () => {
297
+ const { synkConfig } = await Promise.resolve().then(() => __importStar(require('../synk/config')));
298
+ const { readCredentials, readDaemonState } = await Promise.resolve().then(() => __importStar(require('../synk/persistence')));
299
+ const axios = (await Promise.resolve().then(() => __importStar(require('axios')))).default;
300
+ console.log('');
301
+ console.log(chalk_1.default.cyan.bold(' ekkOS_synk Doctor'));
302
+ console.log('');
303
+ // Check config
304
+ console.log(chalk_1.default.gray(' Server URL: ') + synkConfig.serverUrl);
305
+ console.log(chalk_1.default.gray(' Data dir: ') + synkConfig.synkHomeDir);
306
+ // Check credentials
307
+ const credentials = await readCredentials();
308
+ if (credentials) {
309
+ console.log(` ${chalk_1.default.green('✓')} Credentials found`);
310
+ }
311
+ else {
312
+ console.log(` ${chalk_1.default.red('✗')} No credentials — run "ekkos synk auth"`);
313
+ return;
314
+ }
315
+ // Check server connectivity
316
+ try {
317
+ const response = await axios.get(synkConfig.serverUrl, { timeout: 5000 });
318
+ console.log(` ${chalk_1.default.green('✓')} Server reachable`);
319
+ }
320
+ catch (error) {
321
+ console.log(` ${chalk_1.default.red('✗')} Server unreachable: ${error instanceof Error ? error.message : 'Unknown error'}`);
322
+ }
323
+ // Check daemon
324
+ const daemonState = await readDaemonState();
325
+ if (daemonState) {
326
+ try {
327
+ process.kill(daemonState.pid, 0);
328
+ console.log(` ${chalk_1.default.green('✓')} Daemon running (PID ${daemonState.pid})`);
329
+ }
330
+ catch {
331
+ console.log(` ${chalk_1.default.yellow('!')} Stale daemon state (PID ${daemonState.pid} not running)`);
332
+ }
333
+ }
334
+ else {
335
+ console.log(` ${chalk_1.default.gray('○')} Daemon not running`);
336
+ }
337
+ console.log('');
338
+ });
339
+ }
@@ -1,11 +1,12 @@
1
1
  /**
2
- * DEPRECATED: Hook configuration removed in hookless architecture migration.
3
- * Claude Code settings.json will NOT have any hooks entries written by ekkOS.
4
- * The CLI + proxy handle everything — hooks are no longer needed.
2
+ * Claude Code settings.json management for ekkOS.
3
+ * - Disables Claude's built-in auto-memory (ekkOS replaces it with 11-layer memory)
4
+ * - Cleans up any legacy hooks entries
5
5
  */
6
6
  /**
7
- * Deploy Claude Code settings.json — no-op for hooks.
8
- * Preserves any existing settings but does NOT write any hooks configuration.
7
+ * Deploy Claude Code settings.json — disables auto-memory and cleans up legacy hooks.
8
+ * ekkOS provides its own memory system via MCP, so Claude's built-in auto-memory
9
+ * is redundant and wastes ~1K tokens/turn on duplicate context.
9
10
  */
10
11
  export declare function deployClaudeSettings(): void;
11
12
  /**
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  /**
3
- * DEPRECATED: Hook configuration removed in hookless architecture migration.
4
- * Claude Code settings.json will NOT have any hooks entries written by ekkOS.
5
- * The CLI + proxy handle everything — hooks are no longer needed.
3
+ * Claude Code settings.json management for ekkOS.
4
+ * - Disables Claude's built-in auto-memory (ekkOS replaces it with 11-layer memory)
5
+ * - Cleans up any legacy hooks entries
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.deployClaudeSettings = deployClaudeSettings;
@@ -10,28 +10,38 @@ exports.areHooksConfigured = areHooksConfigured;
10
10
  const fs_1 = require("fs");
11
11
  const platform_1 = require("../utils/platform");
12
12
  /**
13
- * Deploy Claude Code settings.json — no-op for hooks.
14
- * Preserves any existing settings but does NOT write any hooks configuration.
13
+ * Deploy Claude Code settings.json — disables auto-memory and cleans up legacy hooks.
14
+ * ekkOS provides its own memory system via MCP, so Claude's built-in auto-memory
15
+ * is redundant and wastes ~1K tokens/turn on duplicate context.
15
16
  */
16
17
  function deployClaudeSettings() {
17
18
  // Ensure .claude directory exists
18
19
  if (!(0, fs_1.existsSync)(platform_1.CLAUDE_DIR)) {
19
20
  (0, fs_1.mkdirSync)(platform_1.CLAUDE_DIR, { recursive: true });
20
21
  }
21
- // Read existing settings (if any) but do NOT add or modify hooks
22
- if (!(0, fs_1.existsSync)(platform_1.CLAUDE_SETTINGS)) {
23
- return; // Nothing to do — don't create an empty file
24
- }
25
- try {
26
- const settings = JSON.parse((0, fs_1.readFileSync)(platform_1.CLAUDE_SETTINGS, 'utf-8'));
27
- // Remove any previously-installed ekkOS hooks entries
28
- if ('hooks' in settings) {
29
- delete settings.hooks;
30
- (0, fs_1.writeFileSync)(platform_1.CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
22
+ let settings = {};
23
+ if ((0, fs_1.existsSync)(platform_1.CLAUDE_SETTINGS)) {
24
+ try {
25
+ settings = JSON.parse((0, fs_1.readFileSync)(platform_1.CLAUDE_SETTINGS, 'utf-8'));
26
+ }
27
+ catch {
28
+ // Invalid JSON start fresh
29
+ settings = {};
31
30
  }
32
31
  }
33
- catch {
34
- // Invalid JSON or read error leave the file alone
32
+ let changed = false;
33
+ // Disable Claude's built-in auto-memoryekkOS replaces it
34
+ if (settings.autoMemoryEnabled !== false) {
35
+ settings.autoMemoryEnabled = false;
36
+ changed = true;
37
+ }
38
+ // Remove any previously-installed ekkOS hooks entries
39
+ if ('hooks' in settings) {
40
+ delete settings.hooks;
41
+ changed = true;
42
+ }
43
+ if (changed) {
44
+ (0, fs_1.writeFileSync)(platform_1.CLAUDE_SETTINGS, JSON.stringify(settings, null, 2));
35
45
  }
36
46
  }
37
47
  /**
package/dist/index.js CHANGED
@@ -47,14 +47,13 @@ const doctor_1 = require("./commands/doctor");
47
47
  const stream_1 = require("./commands/stream");
48
48
  // DEPRECATED: Hooks removed in hookless architecture migration
49
49
  // hooksInstall, hooksVerify, hooksStatus no longer called — `hooks` command prints a deprecation notice.
50
- const setup_remote_1 = require("./commands/setup-remote");
51
- const agent_1 = require("./commands/agent");
52
50
  const state_1 = require("./utils/state");
53
51
  const index_1 = require("./commands/usage/index");
54
52
  const dashboard_1 = require("./commands/dashboard");
55
53
  const swarm_1 = require("./commands/swarm");
56
54
  const swarm_dashboard_1 = require("./commands/swarm-dashboard");
57
55
  const swarm_setup_1 = require("./commands/swarm-setup");
56
+ const synk_1 = require("./commands/synk");
58
57
  const chalk_1 = __importDefault(require("chalk"));
59
58
  const fs = __importStar(require("fs"));
60
59
  const path = __importStar(require("path"));
@@ -174,11 +173,10 @@ commander_1.program
174
173
  ],
175
174
  },
176
175
  {
177
- title: 'Remote Terminal',
176
+ title: 'Synk (Remote Session Sync)',
178
177
  icon: '▸',
179
178
  commands: [
180
- { name: 'setup-remote', desc: 'Set up remote access (run Claude on your PC from anywhere)' },
181
- { name: 'agent', desc: 'Manage the remote terminal agent (start, stop, status, logs)' },
179
+ { name: 'synk', desc: 'Remote session sync control Claude Code from anywhere' },
182
180
  ],
183
181
  },
184
182
  {
@@ -224,14 +222,19 @@ commander_1.program
224
222
  .option('-i, --ide <ide>', 'IDE to setup (claude, cursor, windsurf, all)')
225
223
  .option('-k, --key <key>', 'Use API key instead of device auth')
226
224
  .option('-f, --force', 'Force re-authentication and overwrite existing config')
225
+ .option('-q, --quick', 'Quick setup: auto-detect IDE, use defaults, only prompt for API key if missing')
227
226
  .option('--skip-hooks', '[DEPRECATED] Hooks are no longer deployed; this flag is a no-op')
228
227
  .option('--skip-skills', 'Skip skills deployment')
229
228
  .action(init_1.init);
230
229
  // Status command
231
230
  commander_1.program
232
231
  .command('status')
233
- .description('Show your ekkOS memory status and installation info')
234
- .action(status_1.status);
232
+ .description('Show live session metrics and memory status')
233
+ .option('-w, --watch', 'Watch mode — refresh session panel every 2s')
234
+ .option('--json', 'Output raw metrics JSON (no memory API call)')
235
+ .action((options) => {
236
+ (0, status_1.status)({ watch: options.watch, json: options.json });
237
+ });
235
238
  // Test command
236
239
  commander_1.program
237
240
  .command('test')
@@ -382,82 +385,9 @@ commander_1.program
382
385
  });
383
386
  });
384
387
  // ============================================================================
385
- // REMOTE TERMINAL COMMANDS
388
+ // SYNK COMMANDS (Remote Session Sync)
386
389
  // ============================================================================
387
- // Setup remote - one-command setup for remote terminal access
388
- commander_1.program
389
- .command('setup-remote')
390
- .description('Set up remote terminal access (run Claude on your PC from anywhere)')
391
- .option('-f, --force', 'Force re-pairing even if already paired')
392
- .option('--skip-service', 'Skip installing background service')
393
- .option('-v, --verbose', 'Show detailed output')
394
- .action((options) => {
395
- (0, setup_remote_1.setupRemote)({
396
- force: options.force,
397
- skipService: options.skipService,
398
- verbose: options.verbose,
399
- });
400
- });
401
- // Agent command - manage the background agent
402
- const agentCmd = commander_1.program
403
- .command('agent')
404
- .description('Manage the remote terminal agent');
405
- agentCmd
406
- .command('daemon')
407
- .description('Run the agent daemon (used by system service)')
408
- .option('-v, --verbose', 'Show verbose output')
409
- .action((options) => {
410
- (0, agent_1.agentDaemon)({ verbose: options.verbose });
411
- });
412
- agentCmd
413
- .command('start')
414
- .description('Start the agent service')
415
- .option('-v, --verbose', 'Show verbose output')
416
- .action((options) => {
417
- (0, agent_1.agentStart)({ verbose: options.verbose });
418
- });
419
- agentCmd
420
- .command('stop')
421
- .description('Stop the agent service')
422
- .option('-v, --verbose', 'Show verbose output')
423
- .action((options) => {
424
- (0, agent_1.agentStop)({ verbose: options.verbose });
425
- });
426
- agentCmd
427
- .command('restart')
428
- .description('Restart the agent service')
429
- .option('-v, --verbose', 'Show verbose output')
430
- .action((options) => {
431
- (0, agent_1.agentRestart)({ verbose: options.verbose });
432
- });
433
- agentCmd
434
- .command('status')
435
- .description('Check agent status and connection')
436
- .option('-v, --verbose', 'Show verbose output')
437
- .action((options) => {
438
- (0, agent_1.agentStatus)({ verbose: options.verbose });
439
- });
440
- agentCmd
441
- .command('uninstall')
442
- .description('Remove the agent service and unpair device')
443
- .option('-v, --verbose', 'Show verbose output')
444
- .action((options) => {
445
- (0, agent_1.agentUninstall)({ verbose: options.verbose });
446
- });
447
- agentCmd
448
- .command('logs')
449
- .description('Show agent logs')
450
- .option('-f, --follow', 'Follow log output (like tail -f)')
451
- .action((options) => {
452
- (0, agent_1.agentLogs)({ follow: options.follow });
453
- });
454
- agentCmd
455
- .command('health')
456
- .description('Check agent daemon health and diagnose connection issues')
457
- .option('-j, --json', 'Output machine-readable JSON')
458
- .action((options) => {
459
- (0, agent_1.agentHealth)({ json: options.json });
460
- });
390
+ (0, synk_1.registerSynkCommands)(commander_1.program);
461
391
  // Swarm command - manage Q-learning routing
462
392
  const swarmCmd = commander_1.program
463
393
  .command('swarm')
@@ -13,7 +13,7 @@ interface SessionNameResolution {
13
13
  encodedProjectPath: string;
14
14
  startedAt?: string;
15
15
  }
16
- /** Detect ekkOS 3-word session names like "lit-lex-zip" */
16
+ /** Detect ekkOS 3-word session names like "lit-lex-zip" or "ink-net-wag-235" */
17
17
  export declare function isEkkosSessionName(name: string): boolean;
18
18
  /** Resolve an ekkOS session name to a JSONL UUID */
19
19
  export declare function resolveSessionName(name: string): SessionNameResolution | null;
@@ -74,12 +74,14 @@ function calculateTurnCost(model, usage) {
74
74
  (usage.cache_creation_tokens / 1000000) * p.cacheWrite +
75
75
  (usage.cache_read_tokens / 1000000) * p.cacheRead);
76
76
  }
77
- /** Detect ekkOS 3-word session names like "lit-lex-zip" */
77
+ /** Detect ekkOS 3-word session names like "lit-lex-zip" or "ink-net-wag-235" */
78
78
  function isEkkosSessionName(name) {
79
- return /^[a-z]+-[a-z]+-[a-z]+$/.test(name);
79
+ return /^[a-z]+-[a-z]+-[a-z]+(-\d+)?$/.test(name);
80
80
  }
81
81
  function encodeProjectPath(projectPath) {
82
- return projectPath.replace(/\//g, '-');
82
+ // Claude Code replaces all non-alphanumeric chars with '-' in project dir names.
83
+ // This must match Claude's encoding (e.g., /Volumes/ekkOS_Drive → -Volumes-ekkOS-Drive).
84
+ return projectPath.replace(/[^a-zA-Z0-9]/g, '-');
83
85
  }
84
86
  /** Resolve an ekkOS session name to a JSONL UUID */
85
87
  function resolveSessionName(name) {
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Local-First Mode — barrel export
3
+ *
4
+ * Phase 6 of the ekkOS Leadership Plan.
5
+ * Provides offline-capable memory, fallback logic, sync, and local embeddings.
6
+ */
7
+ export { LocalMemoryStore, localStore, } from './sqlite-store';
8
+ export type { Pattern, Directive, EpisodicMemory, SyncQueueItem, StoreStats, } from './sqlite-store';
9
+ export { callWithFallback, isOfflineFallbackReady, OFFLINE_CAPABLE_TOOLS, } from './offline-fallback';
10
+ export type { ToolCallResult, RemoteCallFn, } from './offline-fallback';
11
+ export { SyncEngine, createSyncEngine, } from './sync-engine';
12
+ export type { SyncResult, } from './sync-engine';
13
+ export { generateLocalEmbedding, cosineSimilarity, searchByEmbedding, isEmbeddingAvailable, } from './local-embeddings';
14
+ export type { SimilarityResult, } from './local-embeddings';
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * Local-First Mode — barrel export
4
+ *
5
+ * Phase 6 of the ekkOS Leadership Plan.
6
+ * Provides offline-capable memory, fallback logic, sync, and local embeddings.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.isEmbeddingAvailable = exports.searchByEmbedding = exports.cosineSimilarity = exports.generateLocalEmbedding = exports.createSyncEngine = exports.SyncEngine = exports.OFFLINE_CAPABLE_TOOLS = exports.isOfflineFallbackReady = exports.callWithFallback = exports.localStore = exports.LocalMemoryStore = void 0;
10
+ // SQLite memory store (Phase 6A)
11
+ var sqlite_store_1 = require("./sqlite-store");
12
+ Object.defineProperty(exports, "LocalMemoryStore", { enumerable: true, get: function () { return sqlite_store_1.LocalMemoryStore; } });
13
+ Object.defineProperty(exports, "localStore", { enumerable: true, get: function () { return sqlite_store_1.localStore; } });
14
+ // Offline MCP fallback (Phase 6B)
15
+ var offline_fallback_1 = require("./offline-fallback");
16
+ Object.defineProperty(exports, "callWithFallback", { enumerable: true, get: function () { return offline_fallback_1.callWithFallback; } });
17
+ Object.defineProperty(exports, "isOfflineFallbackReady", { enumerable: true, get: function () { return offline_fallback_1.isOfflineFallbackReady; } });
18
+ Object.defineProperty(exports, "OFFLINE_CAPABLE_TOOLS", { enumerable: true, get: function () { return offline_fallback_1.OFFLINE_CAPABLE_TOOLS; } });
19
+ // Sync engine (Phase 6C)
20
+ var sync_engine_1 = require("./sync-engine");
21
+ Object.defineProperty(exports, "SyncEngine", { enumerable: true, get: function () { return sync_engine_1.SyncEngine; } });
22
+ Object.defineProperty(exports, "createSyncEngine", { enumerable: true, get: function () { return sync_engine_1.createSyncEngine; } });
23
+ // Local embeddings (Phase 6D)
24
+ var local_embeddings_1 = require("./local-embeddings");
25
+ Object.defineProperty(exports, "generateLocalEmbedding", { enumerable: true, get: function () { return local_embeddings_1.generateLocalEmbedding; } });
26
+ Object.defineProperty(exports, "cosineSimilarity", { enumerable: true, get: function () { return local_embeddings_1.cosineSimilarity; } });
27
+ Object.defineProperty(exports, "searchByEmbedding", { enumerable: true, get: function () { return local_embeddings_1.searchByEmbedding; } });
28
+ Object.defineProperty(exports, "isEmbeddingAvailable", { enumerable: true, get: function () { return local_embeddings_1.isEmbeddingAvailable; } });