loopsy 1.0.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.
Files changed (262) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +425 -0
  3. package/dist/cli/commands/connect.d.ts +2 -0
  4. package/dist/cli/commands/connect.d.ts.map +1 -0
  5. package/dist/cli/commands/connect.js +120 -0
  6. package/dist/cli/commands/connect.js.map +1 -0
  7. package/dist/cli/commands/context.d.ts +2 -0
  8. package/dist/cli/commands/context.d.ts.map +1 -0
  9. package/dist/cli/commands/context.js +39 -0
  10. package/dist/cli/commands/context.js.map +1 -0
  11. package/dist/cli/commands/daemon.d.ts +4 -0
  12. package/dist/cli/commands/daemon.d.ts.map +1 -0
  13. package/dist/cli/commands/daemon.js +55 -0
  14. package/dist/cli/commands/daemon.js.map +1 -0
  15. package/dist/cli/commands/dashboard.d.ts +2 -0
  16. package/dist/cli/commands/dashboard.d.ts.map +1 -0
  17. package/dist/cli/commands/dashboard.js +24 -0
  18. package/dist/cli/commands/dashboard.js.map +1 -0
  19. package/dist/cli/commands/doctor.d.ts +2 -0
  20. package/dist/cli/commands/doctor.d.ts.map +1 -0
  21. package/dist/cli/commands/doctor.js +130 -0
  22. package/dist/cli/commands/doctor.js.map +1 -0
  23. package/dist/cli/commands/exec.d.ts +2 -0
  24. package/dist/cli/commands/exec.d.ts.map +1 -0
  25. package/dist/cli/commands/exec.js +34 -0
  26. package/dist/cli/commands/exec.js.map +1 -0
  27. package/dist/cli/commands/init.d.ts +2 -0
  28. package/dist/cli/commands/init.d.ts.map +1 -0
  29. package/dist/cli/commands/init.js +71 -0
  30. package/dist/cli/commands/init.js.map +1 -0
  31. package/dist/cli/commands/key.d.ts +2 -0
  32. package/dist/cli/commands/key.d.ts.map +1 -0
  33. package/dist/cli/commands/key.js +39 -0
  34. package/dist/cli/commands/key.js.map +1 -0
  35. package/dist/cli/commands/logs.d.ts +2 -0
  36. package/dist/cli/commands/logs.d.ts.map +1 -0
  37. package/dist/cli/commands/logs.js +26 -0
  38. package/dist/cli/commands/logs.js.map +1 -0
  39. package/dist/cli/commands/mcp.d.ts +4 -0
  40. package/dist/cli/commands/mcp.d.ts.map +1 -0
  41. package/dist/cli/commands/mcp.js +70 -0
  42. package/dist/cli/commands/mcp.js.map +1 -0
  43. package/dist/cli/commands/pair.d.ts +6 -0
  44. package/dist/cli/commands/pair.d.ts.map +1 -0
  45. package/dist/cli/commands/pair.js +208 -0
  46. package/dist/cli/commands/pair.js.map +1 -0
  47. package/dist/cli/commands/peers.d.ts +2 -0
  48. package/dist/cli/commands/peers.d.ts.map +1 -0
  49. package/dist/cli/commands/peers.js +29 -0
  50. package/dist/cli/commands/peers.js.map +1 -0
  51. package/dist/cli/commands/service/linux.d.ts +7 -0
  52. package/dist/cli/commands/service/linux.d.ts.map +1 -0
  53. package/dist/cli/commands/service/linux.js +86 -0
  54. package/dist/cli/commands/service/linux.js.map +1 -0
  55. package/dist/cli/commands/service/macos.d.ts +7 -0
  56. package/dist/cli/commands/service/macos.d.ts.map +1 -0
  57. package/dist/cli/commands/service/macos.js +83 -0
  58. package/dist/cli/commands/service/macos.js.map +1 -0
  59. package/dist/cli/commands/service/windows.d.ts +7 -0
  60. package/dist/cli/commands/service/windows.d.ts.map +1 -0
  61. package/dist/cli/commands/service/windows.js +52 -0
  62. package/dist/cli/commands/service/windows.js.map +1 -0
  63. package/dist/cli/commands/service.d.ts +4 -0
  64. package/dist/cli/commands/service.d.ts.map +1 -0
  65. package/dist/cli/commands/service.js +68 -0
  66. package/dist/cli/commands/service.js.map +1 -0
  67. package/dist/cli/commands/session.d.ts +8 -0
  68. package/dist/cli/commands/session.d.ts.map +1 -0
  69. package/dist/cli/commands/session.js +270 -0
  70. package/dist/cli/commands/session.js.map +1 -0
  71. package/dist/cli/commands/transfer.d.ts +3 -0
  72. package/dist/cli/commands/transfer.d.ts.map +1 -0
  73. package/dist/cli/commands/transfer.js +57 -0
  74. package/dist/cli/commands/transfer.js.map +1 -0
  75. package/dist/cli/index.d.ts +3 -0
  76. package/dist/cli/index.d.ts.map +1 -0
  77. package/dist/cli/index.js +89 -0
  78. package/dist/cli/index.js.map +1 -0
  79. package/dist/cli/package-root.d.ts +27 -0
  80. package/dist/cli/package-root.d.ts.map +1 -0
  81. package/dist/cli/package-root.js +54 -0
  82. package/dist/cli/package-root.js.map +1 -0
  83. package/dist/cli/utils.d.ts +11 -0
  84. package/dist/cli/utils.d.ts.map +1 -0
  85. package/dist/cli/utils.js +48 -0
  86. package/dist/cli/utils.js.map +1 -0
  87. package/dist/daemon/config.d.ts +4 -0
  88. package/dist/daemon/config.d.ts.map +1 -0
  89. package/dist/daemon/config.js +58 -0
  90. package/dist/daemon/config.js.map +1 -0
  91. package/dist/daemon/hooks/permission-hook.mjs +108 -0
  92. package/dist/daemon/index.d.ts +3 -0
  93. package/dist/daemon/index.d.ts.map +1 -0
  94. package/dist/daemon/index.js +3 -0
  95. package/dist/daemon/index.js.map +1 -0
  96. package/dist/daemon/main.d.ts +3 -0
  97. package/dist/daemon/main.d.ts.map +1 -0
  98. package/dist/daemon/main.js +28 -0
  99. package/dist/daemon/main.js.map +1 -0
  100. package/dist/daemon/middleware/auth.d.ts +3 -0
  101. package/dist/daemon/middleware/auth.d.ts.map +1 -0
  102. package/dist/daemon/middleware/auth.js +22 -0
  103. package/dist/daemon/middleware/auth.js.map +1 -0
  104. package/dist/daemon/routes/ai-tasks.d.ts +4 -0
  105. package/dist/daemon/routes/ai-tasks.d.ts.map +1 -0
  106. package/dist/daemon/routes/ai-tasks.js +146 -0
  107. package/dist/daemon/routes/ai-tasks.js.map +1 -0
  108. package/dist/daemon/routes/context.d.ts +4 -0
  109. package/dist/daemon/routes/context.d.ts.map +1 -0
  110. package/dist/daemon/routes/context.js +49 -0
  111. package/dist/daemon/routes/context.js.map +1 -0
  112. package/dist/daemon/routes/execute.d.ts +4 -0
  113. package/dist/daemon/routes/execute.d.ts.map +1 -0
  114. package/dist/daemon/routes/execute.js +74 -0
  115. package/dist/daemon/routes/execute.js.map +1 -0
  116. package/dist/daemon/routes/health.d.ts +15 -0
  117. package/dist/daemon/routes/health.d.ts.map +1 -0
  118. package/dist/daemon/routes/health.js +38 -0
  119. package/dist/daemon/routes/health.js.map +1 -0
  120. package/dist/daemon/routes/pair.d.ts +11 -0
  121. package/dist/daemon/routes/pair.d.ts.map +1 -0
  122. package/dist/daemon/routes/pair.js +149 -0
  123. package/dist/daemon/routes/pair.js.map +1 -0
  124. package/dist/daemon/routes/peers.d.ts +5 -0
  125. package/dist/daemon/routes/peers.d.ts.map +1 -0
  126. package/dist/daemon/routes/peers.js +69 -0
  127. package/dist/daemon/routes/peers.js.map +1 -0
  128. package/dist/daemon/routes/transfer.d.ts +4 -0
  129. package/dist/daemon/routes/transfer.d.ts.map +1 -0
  130. package/dist/daemon/routes/transfer.js +135 -0
  131. package/dist/daemon/routes/transfer.js.map +1 -0
  132. package/dist/daemon/server.d.ts +8 -0
  133. package/dist/daemon/server.d.ts.map +1 -0
  134. package/dist/daemon/server.js +170 -0
  135. package/dist/daemon/server.js.map +1 -0
  136. package/dist/daemon/services/ai-task-manager.d.ts +56 -0
  137. package/dist/daemon/services/ai-task-manager.d.ts.map +1 -0
  138. package/dist/daemon/services/ai-task-manager.js +491 -0
  139. package/dist/daemon/services/ai-task-manager.js.map +1 -0
  140. package/dist/daemon/services/audit-logger.d.ts +16 -0
  141. package/dist/daemon/services/audit-logger.d.ts.map +1 -0
  142. package/dist/daemon/services/audit-logger.js +23 -0
  143. package/dist/daemon/services/audit-logger.js.map +1 -0
  144. package/dist/daemon/services/context-store.d.ts +17 -0
  145. package/dist/daemon/services/context-store.d.ts.map +1 -0
  146. package/dist/daemon/services/context-store.js +97 -0
  147. package/dist/daemon/services/context-store.js.map +1 -0
  148. package/dist/daemon/services/job-manager.d.ts +19 -0
  149. package/dist/daemon/services/job-manager.d.ts.map +1 -0
  150. package/dist/daemon/services/job-manager.js +92 -0
  151. package/dist/daemon/services/job-manager.js.map +1 -0
  152. package/dist/daemon/services/tls-manager.d.ts +33 -0
  153. package/dist/daemon/services/tls-manager.d.ts.map +1 -0
  154. package/dist/daemon/services/tls-manager.js +114 -0
  155. package/dist/daemon/services/tls-manager.js.map +1 -0
  156. package/dist/daemon/utils/which.d.ts +2 -0
  157. package/dist/daemon/utils/which.d.ts.map +1 -0
  158. package/dist/daemon/utils/which.js +18 -0
  159. package/dist/daemon/utils/which.js.map +1 -0
  160. package/dist/dashboard/config.d.ts +8 -0
  161. package/dist/dashboard/config.d.ts.map +1 -0
  162. package/dist/dashboard/config.js +22 -0
  163. package/dist/dashboard/config.js.map +1 -0
  164. package/dist/dashboard/public/app.js +120 -0
  165. package/dist/dashboard/public/icon-192.png +0 -0
  166. package/dist/dashboard/public/icon-512.png +0 -0
  167. package/dist/dashboard/public/index.html +85 -0
  168. package/dist/dashboard/public/manifest.json +12 -0
  169. package/dist/dashboard/public/style.css +784 -0
  170. package/dist/dashboard/public/sw.js +31 -0
  171. package/dist/dashboard/public/views/ai-tasks.js +679 -0
  172. package/dist/dashboard/public/views/context.js +167 -0
  173. package/dist/dashboard/public/views/messages.js +263 -0
  174. package/dist/dashboard/public/views/overview.js +228 -0
  175. package/dist/dashboard/public/views/peers.js +136 -0
  176. package/dist/dashboard/public/views/terminal.js +153 -0
  177. package/dist/dashboard/routes/ai-tasks.d.ts +3 -0
  178. package/dist/dashboard/routes/ai-tasks.d.ts.map +1 -0
  179. package/dist/dashboard/routes/ai-tasks.js +193 -0
  180. package/dist/dashboard/routes/ai-tasks.js.map +1 -0
  181. package/dist/dashboard/routes/messages.d.ts +3 -0
  182. package/dist/dashboard/routes/messages.d.ts.map +1 -0
  183. package/dist/dashboard/routes/messages.js +137 -0
  184. package/dist/dashboard/routes/messages.js.map +1 -0
  185. package/dist/dashboard/routes/peer-utils.d.ts +17 -0
  186. package/dist/dashboard/routes/peer-utils.d.ts.map +1 -0
  187. package/dist/dashboard/routes/peer-utils.js +193 -0
  188. package/dist/dashboard/routes/peer-utils.js.map +1 -0
  189. package/dist/dashboard/routes/peers-all.d.ts +3 -0
  190. package/dist/dashboard/routes/peers-all.d.ts.map +1 -0
  191. package/dist/dashboard/routes/peers-all.js +8 -0
  192. package/dist/dashboard/routes/peers-all.js.map +1 -0
  193. package/dist/dashboard/routes/proxy.d.ts +3 -0
  194. package/dist/dashboard/routes/proxy.d.ts.map +1 -0
  195. package/dist/dashboard/routes/proxy.js +59 -0
  196. package/dist/dashboard/routes/proxy.js.map +1 -0
  197. package/dist/dashboard/routes/sessions.d.ts +3 -0
  198. package/dist/dashboard/routes/sessions.d.ts.map +1 -0
  199. package/dist/dashboard/routes/sessions.js +64 -0
  200. package/dist/dashboard/routes/sessions.js.map +1 -0
  201. package/dist/dashboard/routes/sse.d.ts +3 -0
  202. package/dist/dashboard/routes/sse.d.ts.map +1 -0
  203. package/dist/dashboard/routes/sse.js +49 -0
  204. package/dist/dashboard/routes/sse.js.map +1 -0
  205. package/dist/dashboard/routes/status.d.ts +3 -0
  206. package/dist/dashboard/routes/status.d.ts.map +1 -0
  207. package/dist/dashboard/routes/status.js +38 -0
  208. package/dist/dashboard/routes/status.js.map +1 -0
  209. package/dist/dashboard/server.d.ts +3 -0
  210. package/dist/dashboard/server.d.ts.map +1 -0
  211. package/dist/dashboard/server.js +77 -0
  212. package/dist/dashboard/server.js.map +1 -0
  213. package/dist/dashboard/session-manager.d.ts +17 -0
  214. package/dist/dashboard/session-manager.d.ts.map +1 -0
  215. package/dist/dashboard/session-manager.js +225 -0
  216. package/dist/dashboard/session-manager.js.map +1 -0
  217. package/dist/discovery/health-checker.d.ts +15 -0
  218. package/dist/discovery/health-checker.d.ts.map +1 -0
  219. package/dist/discovery/health-checker.js +47 -0
  220. package/dist/discovery/health-checker.js.map +1 -0
  221. package/dist/discovery/index.d.ts +4 -0
  222. package/dist/discovery/index.d.ts.map +1 -0
  223. package/dist/discovery/index.js +4 -0
  224. package/dist/discovery/index.js.map +1 -0
  225. package/dist/discovery/mdns.d.ts +21 -0
  226. package/dist/discovery/mdns.d.ts.map +1 -0
  227. package/dist/discovery/mdns.js +83 -0
  228. package/dist/discovery/mdns.js.map +1 -0
  229. package/dist/discovery/peer-registry.d.ts +18 -0
  230. package/dist/discovery/peer-registry.d.ts.map +1 -0
  231. package/dist/discovery/peer-registry.js +81 -0
  232. package/dist/discovery/peer-registry.js.map +1 -0
  233. package/dist/mcp-server/daemon-client.d.ts +69 -0
  234. package/dist/mcp-server/daemon-client.d.ts.map +1 -0
  235. package/dist/mcp-server/daemon-client.js +281 -0
  236. package/dist/mcp-server/daemon-client.js.map +1 -0
  237. package/dist/mcp-server/index.d.ts +3 -0
  238. package/dist/mcp-server/index.d.ts.map +1 -0
  239. package/dist/mcp-server/index.js +406 -0
  240. package/dist/mcp-server/index.js.map +1 -0
  241. package/dist/protocol/constants.d.ts +66 -0
  242. package/dist/protocol/constants.d.ts.map +1 -0
  243. package/dist/protocol/constants.js +66 -0
  244. package/dist/protocol/constants.js.map +1 -0
  245. package/dist/protocol/errors.d.ts +47 -0
  246. package/dist/protocol/errors.d.ts.map +1 -0
  247. package/dist/protocol/errors.js +62 -0
  248. package/dist/protocol/errors.js.map +1 -0
  249. package/dist/protocol/index.d.ts +5 -0
  250. package/dist/protocol/index.d.ts.map +1 -0
  251. package/dist/protocol/index.js +5 -0
  252. package/dist/protocol/index.js.map +1 -0
  253. package/dist/protocol/schemas.d.ts +209 -0
  254. package/dist/protocol/schemas.d.ts.map +1 -0
  255. package/dist/protocol/schemas.js +115 -0
  256. package/dist/protocol/schemas.js.map +1 -0
  257. package/dist/protocol/types.d.ts +302 -0
  258. package/dist/protocol/types.d.ts.map +1 -0
  259. package/dist/protocol/types.js +2 -0
  260. package/dist/protocol/types.js.map +1 -0
  261. package/package.json +50 -0
  262. package/scripts/postinstall.mjs +42 -0
@@ -0,0 +1,120 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { homedir, networkInterfaces } from 'node:os';
4
+ import { createInterface } from 'node:readline/promises';
5
+ import { parse as parseYaml, stringify as toYaml } from 'yaml';
6
+ import { CONFIG_DIR, CONFIG_FILE, DEFAULT_PORT } from '@loopsy/protocol';
7
+ const CONFIG_PATH = join(homedir(), CONFIG_DIR, CONFIG_FILE);
8
+ function getLanAddresses() {
9
+ const nets = networkInterfaces();
10
+ const addresses = [];
11
+ for (const ifaces of Object.values(nets)) {
12
+ if (!ifaces)
13
+ continue;
14
+ for (const iface of ifaces) {
15
+ if (iface.family === 'IPv4' && !iface.internal) {
16
+ addresses.push(iface.address);
17
+ }
18
+ }
19
+ }
20
+ return addresses;
21
+ }
22
+ async function prompt(rl, question) {
23
+ const answer = await rl.question(question);
24
+ return answer.trim();
25
+ }
26
+ export async function connectCommand() {
27
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
28
+ try {
29
+ // Load config
30
+ let config;
31
+ try {
32
+ const raw = await readFile(CONFIG_PATH, 'utf-8');
33
+ config = parseYaml(raw);
34
+ }
35
+ catch {
36
+ console.log('Config not found. Run "loopsy init" first.');
37
+ return;
38
+ }
39
+ const myKey = config.auth?.apiKey ?? 'unknown';
40
+ const myAddresses = getLanAddresses();
41
+ // Step 1: Show this machine's info
42
+ console.log('');
43
+ console.log('=== This Machine ===');
44
+ console.log(`IP address(es): ${myAddresses.join(', ') || 'unknown'}`);
45
+ console.log(`Port: ${config.server?.port ?? DEFAULT_PORT}`);
46
+ console.log(`API Key: ${myKey}`);
47
+ console.log('');
48
+ console.log('Share the above IP and API key with the other machine.');
49
+ console.log('');
50
+ // Step 2: Get peer info
51
+ const peerIp = await prompt(rl, 'Enter the peer\'s IP address: ');
52
+ if (!peerIp) {
53
+ console.log('No IP provided, aborting.');
54
+ return;
55
+ }
56
+ const peerPortStr = await prompt(rl, `Enter the peer's port (default ${DEFAULT_PORT}): `);
57
+ const peerPort = peerPortStr ? parseInt(peerPortStr, 10) : DEFAULT_PORT;
58
+ const peerKey = await prompt(rl, 'Enter the peer\'s API key: ');
59
+ if (!peerKey) {
60
+ console.log('No API key provided, aborting.');
61
+ return;
62
+ }
63
+ const peerName = await prompt(rl, 'Give this peer a name (e.g. windows-pc, macbook): ');
64
+ const name = peerName || `peer-${peerIp}`;
65
+ // Step 3: Update config
66
+ config.auth = config.auth ?? {};
67
+ config.auth.allowedKeys = config.auth.allowedKeys ?? {};
68
+ config.auth.allowedKeys[name] = peerKey;
69
+ config.discovery = config.discovery ?? {};
70
+ config.discovery.manualPeers = config.discovery.manualPeers ?? [];
71
+ // Avoid duplicate manual peers
72
+ const exists = config.discovery.manualPeers.some((p) => p.address === peerIp && p.port === peerPort);
73
+ if (!exists) {
74
+ config.discovery.manualPeers.push({ address: peerIp, port: peerPort });
75
+ }
76
+ await writeFile(CONFIG_PATH, toYaml(config));
77
+ console.log('');
78
+ console.log(`Peer "${name}" added to config.`);
79
+ // Step 4: Test connection
80
+ console.log(`Testing connection to ${peerIp}:${peerPort}...`);
81
+ try {
82
+ const res = await fetch(`http://${peerIp}:${peerPort}/api/v1/health`, {
83
+ signal: AbortSignal.timeout(5000),
84
+ });
85
+ if (res.ok) {
86
+ const data = await res.json();
87
+ console.log(`Connected! Peer node: ${data.nodeId}`);
88
+ }
89
+ else {
90
+ console.log(`Peer responded with HTTP ${res.status}. It may not be running yet.`);
91
+ }
92
+ }
93
+ catch {
94
+ console.log('Could not reach peer. Make sure:');
95
+ console.log(' - The peer has run "loopsy init" and "loopsy start"');
96
+ console.log(' - Both machines are on the same network');
97
+ console.log(` - Port ${peerPort} is not blocked by a firewall`);
98
+ console.log('');
99
+ console.log('The config has been saved. You can retry once the peer is running.');
100
+ }
101
+ // Step 5: Usage examples
102
+ console.log('');
103
+ console.log('=== Ready! ===');
104
+ console.log('');
105
+ console.log('Make sure the daemon is running:');
106
+ console.log(' loopsy start');
107
+ console.log('');
108
+ console.log('Try these commands:');
109
+ console.log(` loopsy exec ${peerIp} -k ${peerKey.slice(0, 8)}... echo hello`);
110
+ console.log(` loopsy context set my_message "Hello from this machine"`);
111
+ console.log(` loopsy peers`);
112
+ console.log('');
113
+ console.log('The other machine should also run "loopsy connect" and enter this');
114
+ console.log('machine\'s IP and API key so both sides can communicate.');
115
+ }
116
+ finally {
117
+ rl.close();
118
+ }
119
+ }
120
+ //# sourceMappingURL=connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function contextCommand(argv: any): Promise<void>;
2
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAEA,wBAAsB,cAAc,CAAC,IAAI,EAAE,GAAG,iBAgC7C"}
@@ -0,0 +1,39 @@
1
+ import { daemonRequest } from '../utils.js';
2
+ export async function contextCommand(argv) {
3
+ const sub = argv._[1];
4
+ try {
5
+ if (sub === 'set') {
6
+ const result = await daemonRequest(`/context/${encodeURIComponent(argv.key)}`, {
7
+ method: 'PUT',
8
+ body: JSON.stringify({ value: argv.value, ttl: argv.ttl }),
9
+ });
10
+ console.log('Context set:', JSON.stringify(result, null, 2));
11
+ }
12
+ else if (sub === 'get') {
13
+ const result = await daemonRequest(`/context/${encodeURIComponent(argv.key)}`);
14
+ console.log(result.value);
15
+ }
16
+ else if (sub === 'delete') {
17
+ await daemonRequest(`/context/${encodeURIComponent(argv.key)}`, { method: 'DELETE' });
18
+ console.log(`Deleted key: ${argv.key}`);
19
+ }
20
+ else {
21
+ // list
22
+ const result = await daemonRequest('/context');
23
+ if (result.entries.length === 0) {
24
+ console.log('No context entries');
25
+ }
26
+ else {
27
+ for (const entry of result.entries) {
28
+ const ttl = entry.expiresAt ? ` (expires in ${Math.round((entry.expiresAt - Date.now()) / 1000)}s)` : '';
29
+ console.log(` ${entry.key} = ${entry.value.slice(0, 80)}${entry.value.length > 80 ? '...' : ''}${ttl}`);
30
+ }
31
+ }
32
+ }
33
+ }
34
+ catch (err) {
35
+ console.error(`Error: ${err.message}`);
36
+ process.exit(1);
37
+ }
38
+ }
39
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAS;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtB,IAAI,CAAC;QACH,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAClB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,YAAY,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;gBAC7E,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;aAC3D,CAAC,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC;aAAM,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,YAAY,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/E,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,aAAa,CAAC,YAAY,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;YACtF,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,OAAO;YACP,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,UAAU,CAAC,CAAC;YAC/C,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBACnC,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;oBACzG,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;gBAC3G,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function startCommand(): Promise<void>;
2
+ export declare function stopCommand(): Promise<void>;
3
+ export declare function statusCommand(): Promise<void>;
4
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAUA,wBAAsB,YAAY,kBAyBjC;AAED,wBAAsB,WAAW,kBAShC;AAED,wBAAsB,aAAa,kBAQlC"}
@@ -0,0 +1,55 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { readFile, writeFile, unlink } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { CONFIG_DIR } from '@loopsy/protocol';
6
+ import { daemonRequest } from '../utils.js';
7
+ import { daemonMainPath } from '../package-root.js';
8
+ const PID_FILE = join(homedir(), CONFIG_DIR, 'daemon.pid');
9
+ export async function startCommand() {
10
+ // Check if already running
11
+ try {
12
+ const pid = parseInt(await readFile(PID_FILE, 'utf-8'), 10);
13
+ process.kill(pid, 0); // Check if process exists
14
+ console.log(`Daemon already running (PID ${pid})`);
15
+ return;
16
+ }
17
+ catch {
18
+ // Not running, start it
19
+ }
20
+ const daemonPath = daemonMainPath();
21
+ const child = spawn('node', [daemonPath], {
22
+ detached: true,
23
+ stdio: 'ignore',
24
+ });
25
+ if (child.pid) {
26
+ await writeFile(PID_FILE, String(child.pid));
27
+ child.unref();
28
+ console.log(`Loopsy daemon started (PID ${child.pid})`);
29
+ }
30
+ else {
31
+ console.error('Failed to start daemon');
32
+ }
33
+ }
34
+ export async function stopCommand() {
35
+ try {
36
+ const pid = parseInt(await readFile(PID_FILE, 'utf-8'), 10);
37
+ process.kill(pid, 'SIGTERM');
38
+ await unlink(PID_FILE);
39
+ console.log(`Daemon stopped (PID ${pid})`);
40
+ }
41
+ catch {
42
+ console.log('Daemon is not running');
43
+ }
44
+ }
45
+ export async function statusCommand() {
46
+ try {
47
+ const result = await daemonRequest('/status');
48
+ console.log(JSON.stringify(result, null, 2));
49
+ }
50
+ catch (err) {
51
+ console.log('Daemon is not running or unreachable');
52
+ console.log(`Error: ${err.message}`);
53
+ }
54
+ }
55
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,2BAA2B;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,0BAA0B;QAChD,OAAO,CAAC,GAAG,CAAC,+BAA+B,GAAG,GAAG,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IAAC,MAAM,CAAC;QACP,wBAAwB;IAC1B,CAAC;IAED,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IAEpC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE;QACxC,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,QAAQ;KAChB,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7C,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,8BAA8B,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;IAC1D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC7B,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,GAAG,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACvC,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function dashboardCommand(argv: any): Promise<void>;
2
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"AAGA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,GAAG,iBAyB/C"}
@@ -0,0 +1,24 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { dashboardServerPath } from '../package-root.js';
3
+ export async function dashboardCommand(argv) {
4
+ const port = argv.port || 19540;
5
+ const serverPath = dashboardServerPath();
6
+ const child = spawn('node', [serverPath, '--port', String(port)], {
7
+ stdio: 'inherit',
8
+ env: process.env,
9
+ });
10
+ child.on('error', (err) => {
11
+ console.error('Failed to start dashboard:', err.message);
12
+ process.exit(1);
13
+ });
14
+ child.on('exit', (code) => {
15
+ process.exit(code ?? 0);
16
+ });
17
+ // Forward SIGINT/SIGTERM to child
18
+ const forward = (signal) => {
19
+ child.kill(signal);
20
+ };
21
+ process.on('SIGINT', () => forward('SIGINT'));
22
+ process.on('SIGTERM', () => forward('SIGTERM'));
23
+ }
24
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAS;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC;IAEhC,MAAM,UAAU,GAAG,mBAAmB,EAAE,CAAC;IAEzC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE;QAChE,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QACxB,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,kCAAkC;IAClC,MAAM,OAAO,GAAG,CAAC,MAAsB,EAAE,EAAE;QACzC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function doctorCommand(): Promise<void>;
2
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAeA,wBAAsB,aAAa,kBAqHlC"}
@@ -0,0 +1,130 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { homedir, platform } from 'node:os';
5
+ import { execSync } from 'node:child_process';
6
+ import { CONFIG_DIR, CONFIG_FILE, TLS_DIR, TLS_CERT_FILE, DEFAULT_PORT } from '@loopsy/protocol';
7
+ import { parse as parseYaml } from 'yaml';
8
+ export async function doctorCommand() {
9
+ const checks = [];
10
+ const loopsyDir = join(homedir(), CONFIG_DIR);
11
+ const configPath = join(loopsyDir, CONFIG_FILE);
12
+ // 1. Config exists
13
+ let config = null;
14
+ if (existsSync(configPath)) {
15
+ try {
16
+ const raw = await readFile(configPath, 'utf-8');
17
+ config = parseYaml(raw);
18
+ checks.push({ name: 'Config', status: 'pass', message: configPath });
19
+ }
20
+ catch (err) {
21
+ checks.push({ name: 'Config', status: 'fail', message: `Invalid YAML: ${err.message}`, fix: 'loopsy init' });
22
+ }
23
+ }
24
+ else {
25
+ checks.push({ name: 'Config', status: 'fail', message: 'Not found', fix: 'loopsy init' });
26
+ }
27
+ // 2. Daemon running
28
+ const port = config?.server?.port ?? DEFAULT_PORT;
29
+ try {
30
+ const res = await fetch(`http://127.0.0.1:${port}/api/v1/health`, {
31
+ signal: AbortSignal.timeout(3000),
32
+ headers: config?.auth?.apiKey ? { Authorization: `Bearer ${config.auth.apiKey}` } : {},
33
+ });
34
+ if (res.ok) {
35
+ checks.push({ name: 'Daemon', status: 'pass', message: `Running on port ${port}` });
36
+ }
37
+ else {
38
+ checks.push({ name: 'Daemon', status: 'fail', message: `HTTP ${res.status}`, fix: 'loopsy start' });
39
+ }
40
+ }
41
+ catch {
42
+ checks.push({ name: 'Daemon', status: 'fail', message: 'Not running', fix: 'loopsy start' });
43
+ }
44
+ // 3. MCP registered
45
+ try {
46
+ execSync('claude --version', { stdio: 'ignore' });
47
+ try {
48
+ const output = execSync('claude mcp list', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
49
+ if (output.includes('loopsy')) {
50
+ checks.push({ name: 'MCP', status: 'pass', message: 'Registered with Claude Code' });
51
+ }
52
+ else {
53
+ checks.push({ name: 'MCP', status: 'warn', message: 'Not registered', fix: 'loopsy mcp add' });
54
+ }
55
+ }
56
+ catch {
57
+ checks.push({ name: 'MCP', status: 'warn', message: 'Could not check', fix: 'loopsy mcp add' });
58
+ }
59
+ }
60
+ catch {
61
+ checks.push({ name: 'MCP', status: 'warn', message: 'Claude Code CLI not found' });
62
+ }
63
+ // 4. TLS
64
+ const tlsCertPath = join(loopsyDir, TLS_DIR, TLS_CERT_FILE);
65
+ if (existsSync(tlsCertPath)) {
66
+ const tlsEnabled = config?.tls?.enabled;
67
+ if (tlsEnabled) {
68
+ checks.push({ name: 'TLS', status: 'pass', message: 'Enabled with certificate' });
69
+ }
70
+ else {
71
+ checks.push({ name: 'TLS', status: 'warn', message: 'Certificate exists but TLS not enabled in config' });
72
+ }
73
+ }
74
+ else {
75
+ checks.push({ name: 'TLS', status: 'warn', message: 'No certificate (optional — set tls.enabled: true in config)' });
76
+ }
77
+ // 5. Peers
78
+ const allowedKeys = config?.auth?.allowedKeys;
79
+ const peerCount = allowedKeys ? Object.keys(allowedKeys).length : 0;
80
+ if (peerCount > 0) {
81
+ checks.push({ name: 'Peers', status: 'pass', message: `${peerCount} peer(s) configured` });
82
+ }
83
+ else {
84
+ checks.push({ name: 'Peers', status: 'warn', message: 'No peers configured', fix: 'loopsy pair' });
85
+ }
86
+ // 6. System service
87
+ const os = platform();
88
+ let serviceEnabled = false;
89
+ if (os === 'darwin') {
90
+ serviceEnabled = existsSync(join(homedir(), 'Library', 'LaunchAgents', 'com.loopsy.daemon.plist'));
91
+ }
92
+ else if (os === 'linux') {
93
+ serviceEnabled = existsSync(join(homedir(), '.config', 'systemd', 'user', 'loopsy.service'));
94
+ }
95
+ else if (os === 'win32') {
96
+ try {
97
+ execSync('schtasks /query /tn "LoopsyDaemon" /fo csv /nh', { stdio: 'pipe' });
98
+ serviceEnabled = true;
99
+ }
100
+ catch { }
101
+ }
102
+ if (serviceEnabled) {
103
+ checks.push({ name: 'Service', status: 'pass', message: 'Auto-start enabled' });
104
+ }
105
+ else {
106
+ checks.push({ name: 'Service', status: 'warn', message: 'Not registered (daemon won\'t auto-start on login)', fix: 'loopsy enable' });
107
+ }
108
+ // Print results
109
+ console.log('');
110
+ console.log('Loopsy Health Check');
111
+ console.log('─'.repeat(50));
112
+ for (const check of checks) {
113
+ const icon = check.status === 'pass' ? 'OK' : check.status === 'fail' ? 'FAIL' : 'WARN';
114
+ const pad = check.name.padEnd(10);
115
+ console.log(` [${icon.padEnd(4)}] ${pad} ${check.message}`);
116
+ if (check.fix && check.status !== 'pass') {
117
+ console.log(` Fix: ${check.fix}`);
118
+ }
119
+ }
120
+ console.log('');
121
+ const failures = checks.filter((c) => c.status === 'fail');
122
+ if (failures.length === 0) {
123
+ console.log('All checks passed!');
124
+ }
125
+ else {
126
+ console.log(`${failures.length} check(s) failed.`);
127
+ process.exitCode = 1;
128
+ }
129
+ }
130
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAS1C,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAEhD,mBAAmB;IACnB,IAAI,MAAM,GAAQ,IAAI,CAAC;IACvB,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAChD,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;QACvE,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC;QAC/G,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC;IAC5F,CAAC;IAED,oBAAoB;IACpB,MAAM,IAAI,GAAG,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI,YAAY,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,oBAAoB,IAAI,gBAAgB,EAAE;YAChE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;YACjC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;SACvF,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,IAAI,EAAE,EAAE,CAAC,CAAC;QACtF,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,CAAC;QACtG,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,oBAAoB;IACpB,IAAI,CAAC;QACH,QAAQ,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,QAAQ,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;YACnG,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC;YACvF,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CAAC;YACjG,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAClG,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,SAAS;IACT,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAC5D,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC;QACxC,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACpF,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,kDAAkD,EAAE,CAAC,CAAC;QAC5G,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,6DAA6D,EAAE,CAAC,CAAC;IACvH,CAAC;IAED,WAAW;IACX,MAAM,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC;IAC9C,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,SAAS,qBAAqB,EAAE,CAAC,CAAC;IAC7F,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC;IACrG,CAAC;IAED,oBAAoB;IACpB,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IACtB,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;QACpB,cAAc,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,yBAAyB,CAAC,CAAC,CAAC;IACrG,CAAC;SAAM,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;QAC1B,cAAc,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC/F,CAAC;SAAM,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,QAAQ,CAAC,gDAAgD,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9E,cAAc,GAAG,IAAI,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC,CAAC;IAClF,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,oDAAoD,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC,CAAC;IACxI,CAAC;IAED,gBAAgB;IAChB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QACxF,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7D,IAAI,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IAC3D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,mBAAmB,CAAC,CAAC;QACnD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function execCommand(argv: any): Promise<void>;
2
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"AAEA,wBAAsB,WAAW,CAAC,IAAI,EAAE,GAAG,iBA+B1C"}
@@ -0,0 +1,34 @@
1
+ import { loadApiKey, parsePeerAddress } from '../utils.js';
2
+ export async function execCommand(argv) {
3
+ const { address, port } = parsePeerAddress(argv.peer);
4
+ const apiKey = argv.key || await loadApiKey();
5
+ const cmd = argv.cmd;
6
+ const command = cmd[0];
7
+ const args = cmd.slice(1);
8
+ try {
9
+ const res = await fetch(`http://${address}:${port}/api/v1/execute`, {
10
+ method: 'POST',
11
+ headers: {
12
+ 'Content-Type': 'application/json',
13
+ Authorization: `Bearer ${apiKey}`,
14
+ },
15
+ body: JSON.stringify({ command, args, timeout: argv.timeout }),
16
+ });
17
+ if (!res.ok) {
18
+ const body = await res.json().catch(() => ({}));
19
+ console.error(`Error: ${body.error?.message ?? res.statusText}`);
20
+ process.exit(1);
21
+ }
22
+ const result = await res.json();
23
+ if (result.stdout)
24
+ process.stdout.write(result.stdout);
25
+ if (result.stderr)
26
+ process.stderr.write(result.stderr);
27
+ process.exit(result.exitCode ?? 0);
28
+ }
29
+ catch (err) {
30
+ console.error(`Failed to execute: ${err.message}`);
31
+ process.exit(1);
32
+ }
33
+ }
34
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAS;IACzC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,MAAM,UAAU,EAAE,CAAC;IAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAe,CAAC;IACjC,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE1B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,UAAU,OAAO,IAAI,IAAI,iBAAiB,EAAE;YAClE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,MAAM,EAAE;aAClC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;SAC/D,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAQ,CAAC;YACvD,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAS,CAAC;QACvC,IAAI,MAAM,CAAC,MAAM;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvD,IAAI,MAAM,CAAC,MAAM;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,sBAAsB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function initCommand(): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AASA,wBAAsB,WAAW,kBAkEhC"}
@@ -0,0 +1,71 @@
1
+ import { writeFile, mkdir, readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { randomBytes } from 'node:crypto';
5
+ import { execSync } from 'node:child_process';
6
+ import { stringify as toYaml } from 'yaml';
7
+ import { CONFIG_DIR, CONFIG_FILE, DEFAULT_PORT, MAX_FILE_SIZE, MAX_CONCURRENT_JOBS, DEFAULT_EXEC_TIMEOUT, RATE_LIMITS } from '@loopsy/protocol';
8
+ import { mcpServerPath } from '../package-root.js';
9
+ export async function initCommand() {
10
+ const configDir = join(homedir(), CONFIG_DIR);
11
+ const configPath = join(configDir, CONFIG_FILE);
12
+ // Check if config already exists
13
+ try {
14
+ await readFile(configPath);
15
+ console.log(`Config already exists at ${configPath}`);
16
+ console.log('Use "loopsy key generate" to regenerate your API key.');
17
+ return;
18
+ }
19
+ catch {
20
+ // Config doesn't exist, create it
21
+ }
22
+ await mkdir(join(configDir, 'logs'), { recursive: true });
23
+ const apiKey = randomBytes(32).toString('hex');
24
+ const config = {
25
+ server: { port: DEFAULT_PORT, host: '0.0.0.0' },
26
+ auth: {
27
+ apiKey,
28
+ allowedKeys: {},
29
+ },
30
+ execution: {
31
+ denylist: ['rm', 'rmdir', 'format', 'mkfs', 'dd', 'shutdown', 'reboot'],
32
+ maxConcurrent: MAX_CONCURRENT_JOBS,
33
+ defaultTimeout: DEFAULT_EXEC_TIMEOUT,
34
+ },
35
+ transfer: {
36
+ allowedPaths: [homedir()],
37
+ deniedPaths: [join(homedir(), '.ssh'), join(homedir(), '.gnupg')],
38
+ maxFileSize: MAX_FILE_SIZE,
39
+ },
40
+ rateLimits: { ...RATE_LIMITS },
41
+ discovery: { enabled: true, manualPeers: [] },
42
+ logging: { level: 'info' },
43
+ };
44
+ await writeFile(configPath, toYaml(config));
45
+ console.log('Loopsy initialized!');
46
+ console.log(`Config: ${configPath}`);
47
+ console.log(`API Key: ${apiKey}`);
48
+ console.log('');
49
+ // Auto-register MCP server with Claude Code if available
50
+ const serverPath = mcpServerPath();
51
+ try {
52
+ execSync('claude --version', { stdio: 'ignore' });
53
+ try {
54
+ execSync('claude mcp remove loopsy', { stdio: 'ignore' });
55
+ }
56
+ catch { }
57
+ execSync(`claude mcp add loopsy -- node ${serverPath}`, { stdio: 'pipe' });
58
+ console.log('MCP server registered with Claude Code');
59
+ }
60
+ catch {
61
+ console.log('To register the MCP server with Claude Code, run:');
62
+ console.log(` claude mcp add loopsy -- node ${serverPath}`);
63
+ }
64
+ console.log('');
65
+ console.log('Next steps:');
66
+ console.log(' 1. Run "loopsy start" to start the daemon');
67
+ console.log(' 2. On the other machine, run "loopsy init" and "loopsy start"');
68
+ console.log(' 3. Run "loopsy pair <ip>" to securely exchange keys');
69
+ console.log(' 4. Peers should auto-discover via mDNS, or add manually with "loopsy peers add <ip>"');
70
+ }
71
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function keyCommand(argv: any): Promise<void>;
2
+ //# sourceMappingURL=key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../../src/commands/key.ts"],"names":[],"mappings":"AASA,wBAAsB,UAAU,CAAC,IAAI,EAAE,GAAG,iBA2BzC"}
@@ -0,0 +1,39 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { randomBytes } from 'node:crypto';
5
+ import { parse as parseYaml, stringify as toYaml } from 'yaml';
6
+ import { CONFIG_DIR, CONFIG_FILE } from '@loopsy/protocol';
7
+ const CONFIG_PATH = join(homedir(), CONFIG_DIR, CONFIG_FILE);
8
+ export async function keyCommand(argv) {
9
+ const sub = argv._[1];
10
+ if (sub === 'generate') {
11
+ const newKey = randomBytes(32).toString('hex');
12
+ try {
13
+ const raw = await readFile(CONFIG_PATH, 'utf-8');
14
+ const config = parseYaml(raw);
15
+ config.auth = config.auth ?? {};
16
+ config.auth.apiKey = newKey;
17
+ await writeFile(CONFIG_PATH, toYaml(config));
18
+ console.log(`New API key generated: ${newKey}`);
19
+ console.log('Restart the daemon for the new key to take effect.');
20
+ }
21
+ catch {
22
+ console.error('Config not found. Run "loopsy init" first.');
23
+ }
24
+ }
25
+ else if (sub === 'show') {
26
+ try {
27
+ const raw = await readFile(CONFIG_PATH, 'utf-8');
28
+ const config = parseYaml(raw);
29
+ console.log(config.auth?.apiKey ?? 'No API key configured');
30
+ }
31
+ catch {
32
+ console.error('Config not found. Run "loopsy init" first.');
33
+ }
34
+ }
35
+ else {
36
+ console.log('Usage: loopsy key <generate|show>');
37
+ }
38
+ }
39
+ //# sourceMappingURL=key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key.js","sourceRoot":"","sources":["../../src/commands/key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,SAAS,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE3D,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AAE7D,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAS;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtB,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAQ,CAAC;YACrC,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YAChC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YAC5B,MAAM,SAAS,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,0BAA0B,MAAM,EAAE,CAAC,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;SAAM,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAQ,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,IAAI,uBAAuB,CAAC,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACnD,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function logsCommand(argv: any): Promise<void>;
2
+ //# sourceMappingURL=logs.d.ts.map