@photon-cli/flux 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +2 -1
- package/dist/cli.d.mts +42 -0
- package/dist/cli.d.ts +42 -0
- package/dist/cli.js +61 -71
- package/dist/cli.js.map +1 -0
- package/dist/cli.mjs +335 -0
- package/dist/cli.mjs.map +1 -0
- package/package.json +1 -1
- package/tsup.config.ts +18 -5
- package/.env +0 -2
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flux CLI - gRPC Client for iMessage Bridge
|
|
3
|
+
* ==========================================
|
|
4
|
+
* This code connects the Flux CLI to the Flux Server's iMessage bridge.
|
|
5
|
+
* Users define their LangChain agent in agent.ts with `export default agent`
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* FluxAgent interface - users must export default an object matching this interface
|
|
9
|
+
* The agent receives a message and returns a response string
|
|
10
|
+
*/
|
|
11
|
+
interface FluxAgent {
|
|
12
|
+
invoke: (input: {
|
|
13
|
+
message: string;
|
|
14
|
+
userPhoneNumber: string;
|
|
15
|
+
imageBase64?: string;
|
|
16
|
+
}) => Promise<string>;
|
|
17
|
+
}
|
|
18
|
+
interface IncomingMessage {
|
|
19
|
+
userPhoneNumber: string;
|
|
20
|
+
text: string;
|
|
21
|
+
imageBase64?: string;
|
|
22
|
+
chatGuid: string;
|
|
23
|
+
messageGuid: string;
|
|
24
|
+
}
|
|
25
|
+
interface OutgoingMessage {
|
|
26
|
+
userPhoneNumber: string;
|
|
27
|
+
text: string;
|
|
28
|
+
chatGuid?: string;
|
|
29
|
+
}
|
|
30
|
+
declare class FluxClient {
|
|
31
|
+
private client;
|
|
32
|
+
private phoneNumber;
|
|
33
|
+
private onMessage;
|
|
34
|
+
constructor(phoneNumber: string, onMessage: (message: IncomingMessage) => Promise<string | void>);
|
|
35
|
+
connect(): Promise<void>;
|
|
36
|
+
register(): Promise<boolean>;
|
|
37
|
+
private startMessageStream;
|
|
38
|
+
sendMessage(to: string, text: string, chatGuid?: string): Promise<boolean>;
|
|
39
|
+
disconnect(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { type FluxAgent, FluxClient, type IncomingMessage, type OutgoingMessage };
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flux CLI - gRPC Client for iMessage Bridge
|
|
3
|
+
* ==========================================
|
|
4
|
+
* This code connects the Flux CLI to the Flux Server's iMessage bridge.
|
|
5
|
+
* Users define their LangChain agent in agent.ts with `export default agent`
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* FluxAgent interface - users must export default an object matching this interface
|
|
9
|
+
* The agent receives a message and returns a response string
|
|
10
|
+
*/
|
|
11
|
+
interface FluxAgent {
|
|
12
|
+
invoke: (input: {
|
|
13
|
+
message: string;
|
|
14
|
+
userPhoneNumber: string;
|
|
15
|
+
imageBase64?: string;
|
|
16
|
+
}) => Promise<string>;
|
|
17
|
+
}
|
|
18
|
+
interface IncomingMessage {
|
|
19
|
+
userPhoneNumber: string;
|
|
20
|
+
text: string;
|
|
21
|
+
imageBase64?: string;
|
|
22
|
+
chatGuid: string;
|
|
23
|
+
messageGuid: string;
|
|
24
|
+
}
|
|
25
|
+
interface OutgoingMessage {
|
|
26
|
+
userPhoneNumber: string;
|
|
27
|
+
text: string;
|
|
28
|
+
chatGuid?: string;
|
|
29
|
+
}
|
|
30
|
+
declare class FluxClient {
|
|
31
|
+
private client;
|
|
32
|
+
private phoneNumber;
|
|
33
|
+
private onMessage;
|
|
34
|
+
constructor(phoneNumber: string, onMessage: (message: IncomingMessage) => Promise<string | void>);
|
|
35
|
+
connect(): Promise<void>;
|
|
36
|
+
register(): Promise<boolean>;
|
|
37
|
+
private startMessageStream;
|
|
38
|
+
sendMessage(to: string, text: string, chatGuid?: string): Promise<boolean>;
|
|
39
|
+
disconnect(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { type FluxAgent, FluxClient, type IncomingMessage, type OutgoingMessage };
|
package/dist/cli.js
CHANGED
|
@@ -1,71 +1,61 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
var
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
if (
|
|
17
|
-
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var betterGrpc = require('better-grpc');
|
|
5
|
+
var cliChat = require('@photon-ai/rapid/cli-chat');
|
|
6
|
+
var fs = require('fs');
|
|
7
|
+
var path = require('path');
|
|
8
|
+
var readline = require('readline');
|
|
9
|
+
var url = require('url');
|
|
10
|
+
|
|
11
|
+
function _interopNamespace(e) {
|
|
12
|
+
if (e && e.__esModule) return e;
|
|
13
|
+
var n = Object.create(null);
|
|
14
|
+
if (e) {
|
|
15
|
+
Object.keys(e).forEach(function (k) {
|
|
16
|
+
if (k !== 'default') {
|
|
17
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
18
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () { return e[k]; }
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
18
24
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
-
mod
|
|
28
|
-
));
|
|
29
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
+
n.default = e;
|
|
26
|
+
return Object.freeze(n);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
30
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
31
|
+
var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
|
|
30
32
|
|
|
31
|
-
// src/cli.ts
|
|
32
|
-
var cli_exports = {};
|
|
33
|
-
__export(cli_exports, {
|
|
34
|
-
FluxClient: () => FluxClient
|
|
35
|
-
});
|
|
36
|
-
module.exports = __toCommonJS(cli_exports);
|
|
37
|
-
var import_better_grpc = require("better-grpc");
|
|
38
|
-
var import_cli_chat = require("@photon-ai/rapid/cli-chat");
|
|
39
|
-
var fs = __toESM(require("fs"));
|
|
40
|
-
var path = __toESM(require("path"));
|
|
41
|
-
var readline = __toESM(require("readline"));
|
|
42
|
-
var import_url = require("url");
|
|
43
33
|
var GRPC_SERVER_ADDRESS = process.env.FLUX_SERVER_ADDRESS || "localhost:50051";
|
|
44
|
-
var CONFIG_DIR =
|
|
45
|
-
var CONFIG_FILE =
|
|
34
|
+
var CONFIG_DIR = path__namespace.join(process.env.HOME || "~", ".flux");
|
|
35
|
+
var CONFIG_FILE = path__namespace.join(CONFIG_DIR, "config.json");
|
|
46
36
|
var AGENT_FILE_NAME = "agent.ts";
|
|
47
37
|
function loadConfig() {
|
|
48
38
|
try {
|
|
49
|
-
if (
|
|
50
|
-
return JSON.parse(
|
|
39
|
+
if (fs__namespace.existsSync(CONFIG_FILE)) {
|
|
40
|
+
return JSON.parse(fs__namespace.readFileSync(CONFIG_FILE, "utf-8"));
|
|
51
41
|
}
|
|
52
42
|
} catch {
|
|
53
43
|
}
|
|
54
44
|
return {};
|
|
55
45
|
}
|
|
56
46
|
function saveConfig(config) {
|
|
57
|
-
if (!
|
|
58
|
-
|
|
47
|
+
if (!fs__namespace.existsSync(CONFIG_DIR)) {
|
|
48
|
+
fs__namespace.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
59
49
|
}
|
|
60
|
-
|
|
50
|
+
fs__namespace.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
61
51
|
}
|
|
62
52
|
function clearConfig() {
|
|
63
|
-
if (
|
|
64
|
-
|
|
53
|
+
if (fs__namespace.existsSync(CONFIG_FILE)) {
|
|
54
|
+
fs__namespace.unlinkSync(CONFIG_FILE);
|
|
65
55
|
}
|
|
66
56
|
}
|
|
67
57
|
async function prompt(question) {
|
|
68
|
-
const rl =
|
|
58
|
+
const rl = readline__namespace.createInterface({
|
|
69
59
|
input: process.stdin,
|
|
70
60
|
output: process.stdout
|
|
71
61
|
});
|
|
@@ -89,7 +79,7 @@ async function login() {
|
|
|
89
79
|
return { received: true };
|
|
90
80
|
}
|
|
91
81
|
});
|
|
92
|
-
const client2 = await
|
|
82
|
+
const client2 = await betterGrpc.createGrpcClient(GRPC_SERVER_ADDRESS, clientImpl);
|
|
93
83
|
const result = await client2.FluxService.validateUser(phoneNumber);
|
|
94
84
|
if (result.error) {
|
|
95
85
|
console.error(`[FLUX] Login failed: ${result.error}`);
|
|
@@ -123,19 +113,19 @@ async function getPhoneNumber() {
|
|
|
123
113
|
}
|
|
124
114
|
function findAgentFile() {
|
|
125
115
|
const cwd = process.cwd();
|
|
126
|
-
const agentPath =
|
|
127
|
-
if (
|
|
116
|
+
const agentPath = path__namespace.join(cwd, AGENT_FILE_NAME);
|
|
117
|
+
if (fs__namespace.existsSync(agentPath)) {
|
|
128
118
|
return agentPath;
|
|
129
119
|
}
|
|
130
|
-
const jsPath =
|
|
131
|
-
if (
|
|
120
|
+
const jsPath = path__namespace.join(cwd, "agent.js");
|
|
121
|
+
if (fs__namespace.existsSync(jsPath)) {
|
|
132
122
|
return jsPath;
|
|
133
123
|
}
|
|
134
124
|
return null;
|
|
135
125
|
}
|
|
136
126
|
async function validateAgentFile(agentPath) {
|
|
137
127
|
try {
|
|
138
|
-
const moduleUrl =
|
|
128
|
+
const moduleUrl = url.pathToFileURL(agentPath).href;
|
|
139
129
|
const agentModule = await import(moduleUrl);
|
|
140
130
|
if (!agentModule.default) {
|
|
141
131
|
return { valid: false, error: "No default export found. Use `export default agent`" };
|
|
@@ -150,18 +140,18 @@ async function validateAgentFile(agentPath) {
|
|
|
150
140
|
}
|
|
151
141
|
}
|
|
152
142
|
async function loadAgent(agentPath) {
|
|
153
|
-
const moduleUrl =
|
|
143
|
+
const moduleUrl = url.pathToFileURL(agentPath).href;
|
|
154
144
|
const agentModule = await import(moduleUrl);
|
|
155
145
|
return agentModule.default;
|
|
156
146
|
}
|
|
157
|
-
var FluxService = class extends
|
|
158
|
-
sendMessage =
|
|
159
|
-
messageStream =
|
|
160
|
-
registerAgent =
|
|
161
|
-
unregisterAgent =
|
|
162
|
-
onIncomingMessage =
|
|
147
|
+
var FluxService = class extends betterGrpc.Service("FluxService") {
|
|
148
|
+
sendMessage = betterGrpc.server();
|
|
149
|
+
messageStream = betterGrpc.bidi();
|
|
150
|
+
registerAgent = betterGrpc.server();
|
|
151
|
+
unregisterAgent = betterGrpc.server();
|
|
152
|
+
onIncomingMessage = betterGrpc.client();
|
|
163
153
|
// Login validation - checks if user exists in Firebase
|
|
164
|
-
validateUser =
|
|
154
|
+
validateUser = betterGrpc.server();
|
|
165
155
|
};
|
|
166
156
|
var FluxClient = class {
|
|
167
157
|
client = null;
|
|
@@ -177,7 +167,7 @@ var FluxClient = class {
|
|
|
177
167
|
return { received: true };
|
|
178
168
|
}
|
|
179
169
|
});
|
|
180
|
-
this.client = await
|
|
170
|
+
this.client = await betterGrpc.createGrpcClient(GRPC_SERVER_ADDRESS, clientImpl);
|
|
181
171
|
console.log(`[FLUX] Connected to server at ${GRPC_SERVER_ADDRESS}`);
|
|
182
172
|
}
|
|
183
173
|
async register() {
|
|
@@ -234,7 +224,7 @@ async function validateCommand() {
|
|
|
234
224
|
console.error("[FLUX] Create an agent.ts file with `export default agent`");
|
|
235
225
|
return false;
|
|
236
226
|
}
|
|
237
|
-
console.log(`[FLUX] Validating ${
|
|
227
|
+
console.log(`[FLUX] Validating ${path__namespace.basename(agentPath)}...`);
|
|
238
228
|
const result = await validateAgentFile(agentPath);
|
|
239
229
|
if (result.valid) {
|
|
240
230
|
console.log("[FLUX] \u2713 Agent is valid!");
|
|
@@ -257,7 +247,7 @@ async function runLocal() {
|
|
|
257
247
|
process.exit(1);
|
|
258
248
|
}
|
|
259
249
|
const agent = await loadAgent(agentPath);
|
|
260
|
-
const chat =
|
|
250
|
+
const chat = cliChat.renderChatUI();
|
|
261
251
|
chat.sendMessage("Welcome to Flux! Your agent is loaded. Type a message to test it.");
|
|
262
252
|
chat.onInput(async (input) => {
|
|
263
253
|
chat.sendMessage("Thinking...");
|
|
@@ -288,7 +278,7 @@ async function runProd() {
|
|
|
288
278
|
console.error(`[FLUX] Agent validation failed: ${validation.error}`);
|
|
289
279
|
process.exit(1);
|
|
290
280
|
}
|
|
291
|
-
console.log(`[FLUX] Loading agent from ${
|
|
281
|
+
console.log(`[FLUX] Loading agent from ${path__namespace.basename(agentPath)}...`);
|
|
292
282
|
const agent = await loadAgent(agentPath);
|
|
293
283
|
console.log("[FLUX] Agent loaded successfully!");
|
|
294
284
|
const flux = new FluxClient(phoneNumber, async (message) => {
|
|
@@ -363,7 +353,7 @@ async function main() {
|
|
|
363
353
|
}
|
|
364
354
|
}
|
|
365
355
|
main().catch(console.error);
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
356
|
+
|
|
357
|
+
exports.FluxClient = FluxClient;
|
|
358
|
+
//# sourceMappingURL=cli.js.map
|
|
359
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"names":["path","fs","readline","client","createGrpcClient","pathToFileURL","Service","server","bidi","renderChatUI"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Flux CLI - gRPC Client for iMessage Bridge\n * ==========================================\n * This code connects the Flux CLI to the Flux Server's iMessage bridge.\n * Users define their LangChain agent in agent.ts with `export default agent`\n */\n\nimport { Service, server, client, bidi, createGrpcClient } from \"better-grpc\";\nimport { renderChatUI } from \"@photon-ai/rapid/cli-chat\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as readline from \"readline\";\nimport { pathToFileURL } from \"url\";\n\n// --- Configuration ---\nconst GRPC_SERVER_ADDRESS = process.env.FLUX_SERVER_ADDRESS || \"localhost:50051\";\nconst CONFIG_DIR = path.join(process.env.HOME || \"~\", \".flux\");\nconst CONFIG_FILE = path.join(CONFIG_DIR, \"config.json\");\nconst AGENT_FILE_NAME = \"agent.ts\";\n\n// --- Auth Storage ---\n\ninterface FluxConfig {\n phoneNumber?: string;\n}\n\nfunction loadConfig(): FluxConfig {\n try {\n if (fs.existsSync(CONFIG_FILE)) {\n return JSON.parse(fs.readFileSync(CONFIG_FILE, \"utf-8\"));\n }\n } catch {}\n return {};\n}\n\nfunction saveConfig(config: FluxConfig): void {\n if (!fs.existsSync(CONFIG_DIR)) {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n }\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n}\n\nfunction clearConfig(): void {\n if (fs.existsSync(CONFIG_FILE)) {\n fs.unlinkSync(CONFIG_FILE);\n }\n}\n\nasync function prompt(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nasync function login(): Promise<string> {\n const phoneNumber = await prompt(\"Enter your phone number (e.g. +15551234567): \");\n if (!phoneNumber.match(/^\\+?[0-9]{10,15}$/)) {\n console.error(\"Invalid phone number format.\");\n process.exit(1);\n }\n\n // Validate with server (checks/creates user in Firebase)\n console.log(\"[FLUX] Validating with server...\");\n try {\n const clientImpl = FluxService.Client({\n async onIncomingMessage() {\n return { received: true };\n },\n });\n const client = await createGrpcClient(GRPC_SERVER_ADDRESS, clientImpl);\n const result = await client.FluxService.validateUser(phoneNumber);\n\n if (result.error) {\n console.error(`[FLUX] Login failed: ${result.error}`);\n process.exit(1);\n }\n\n if (result.created) {\n console.log(`[FLUX] New account created for ${phoneNumber}`);\n } else if (result.exists) {\n console.log(`[FLUX] Welcome back, ${phoneNumber}`);\n }\n\n saveConfig({ phoneNumber });\n console.log(`[FLUX] Logged in as ${phoneNumber}`);\n return phoneNumber;\n } catch (error: any) {\n console.error(`[FLUX] Failed to connect to server: ${error.message}`);\n console.error(`[FLUX] Make sure the Flux server is running at ${GRPC_SERVER_ADDRESS}`);\n process.exit(1);\n }\n}\n\nfunction logout(): void {\n clearConfig();\n console.log(\"[FLUX] Logged out.\");\n}\n\nasync function getPhoneNumber(): Promise<string> {\n const config = loadConfig();\n if (config.phoneNumber) {\n return config.phoneNumber;\n }\n console.log(\"[FLUX] Not logged in.\");\n return await login();\n}\n\n// --- Agent Types ---\n\n/**\n * FluxAgent interface - users must export default an object matching this interface\n * The agent receives a message and returns a response string\n */\nexport interface FluxAgent {\n invoke: (input: { message: string; userPhoneNumber: string; imageBase64?: string }) => Promise<string>;\n}\n\n// --- Agent Loader ---\n\n/**\n * Find agent.ts in the current working directory\n */\nfunction findAgentFile(): string | null {\n const cwd = process.cwd();\n const agentPath = path.join(cwd, AGENT_FILE_NAME);\n\n if (fs.existsSync(agentPath)) {\n return agentPath;\n }\n\n // Also check for agent.js\n const jsPath = path.join(cwd, \"agent.js\");\n if (fs.existsSync(jsPath)) {\n return jsPath;\n }\n\n return null;\n}\n\n/**\n * Validate that the agent file exports a default agent with invoke method\n */\nasync function validateAgentFile(agentPath: string): Promise<{ valid: boolean; error?: string }> {\n try {\n const moduleUrl = pathToFileURL(agentPath).href;\n const agentModule = await import(moduleUrl);\n\n if (!agentModule.default) {\n return { valid: false, error: \"No default export found. Use `export default agent`\" };\n }\n\n const agent = agentModule.default;\n\n if (typeof agent.invoke !== \"function\") {\n return { valid: false, error: \"Agent must have an `invoke` method\" };\n }\n\n return { valid: true };\n } catch (error: any) {\n return { valid: false, error: `Failed to load agent: ${error.message}` };\n }\n}\n\n/**\n * Load the agent from agent.ts\n */\nasync function loadAgent(agentPath: string): Promise<FluxAgent> {\n const moduleUrl = pathToFileURL(agentPath).href;\n const agentModule = await import(moduleUrl);\n return agentModule.default as FluxAgent;\n}\n\n// --- Message Types ---\n\nexport interface IncomingMessage {\n userPhoneNumber: string;\n text: string;\n imageBase64?: string;\n chatGuid: string;\n messageGuid: string;\n}\n\nexport interface OutgoingMessage {\n userPhoneNumber: string;\n text: string;\n chatGuid?: string;\n}\n\n// --- FluxService Definition (must match server) ---\n\nabstract class FluxService extends Service(\"FluxService\") {\n sendMessage = server<(message: OutgoingMessage) => { success: boolean; error?: string }>();\n messageStream = bidi<(message: IncomingMessage | { ack: string }) => void>();\n registerAgent = server<(phoneNumber: string) => { success: boolean; error?: string }>();\n unregisterAgent = server<(phoneNumber: string) => { success: boolean }>();\n onIncomingMessage = client<(message: IncomingMessage) => { received: boolean }>();\n // Login validation - checks if user exists in Firebase\n validateUser = server<(phoneNumber: string) => { exists: boolean; created: boolean; error?: string }>();\n}\n\n// --- FluxClient Class ---\n\nexport class FluxClient {\n private client: Awaited<ReturnType<typeof createGrpcClient>> | null = null;\n private phoneNumber: string;\n private onMessage: (message: IncomingMessage) => Promise<string | void>;\n\n constructor(\n phoneNumber: string,\n onMessage: (message: IncomingMessage) => Promise<string | void>\n ) {\n this.phoneNumber = phoneNumber.replace(/[\\s\\-\\(\\)]/g, \"\");\n this.onMessage = onMessage;\n }\n\n async connect(): Promise<void> {\n const clientImpl = FluxService.Client({\n async onIncomingMessage(message: IncomingMessage) {\n return { received: true };\n },\n });\n\n this.client = await createGrpcClient(GRPC_SERVER_ADDRESS, clientImpl);\n console.log(`[FLUX] Connected to server at ${GRPC_SERVER_ADDRESS}`);\n }\n\n async register(): Promise<boolean> {\n if (!this.client) throw new Error(\"Not connected. Call connect() first.\");\n\n const result = await this.client.FluxService.registerAgent(this.phoneNumber);\n if (result.success) {\n console.log(`[FLUX] Registered agent for ${this.phoneNumber}`);\n this.startMessageStream();\n } else {\n console.error(`[FLUX] Registration failed: ${result.error}`);\n }\n return result.success;\n }\n\n private async startMessageStream(): Promise<void> {\n if (!this.client) return;\n\n (async () => {\n for await (const [message] of this.client!.FluxService.messageStream) {\n if (\"ack\" in message) {\n console.log(`[FLUX] Received ack: ${message.ack}`);\n } else {\n console.log(`[FLUX] Incoming message from ${message.userPhoneNumber}: ${message.text}`);\n\n // Acknowledge receipt\n await this.client!.FluxService.messageStream({ ack: message.messageGuid });\n\n // Process with user's agent and get response\n const response = await this.onMessage(message);\n\n // Send response if agent returned one\n if (response) {\n await this.sendMessage(message.userPhoneNumber, response, message.chatGuid);\n }\n }\n }\n })();\n }\n\n async sendMessage(to: string, text: string, chatGuid?: string): Promise<boolean> {\n if (!this.client) throw new Error(\"Not connected. Call connect() first.\");\n\n const result = await this.client.FluxService.sendMessage({\n userPhoneNumber: to,\n text,\n chatGuid,\n });\n\n if (!result.success) {\n console.error(`[FLUX] Send failed: ${result.error}`);\n }\n return result.success;\n }\n\n async disconnect(): Promise<void> {\n if (!this.client) return;\n\n await this.client.FluxService.unregisterAgent(this.phoneNumber);\n console.log(`[FLUX] Unregistered agent for ${this.phoneNumber}`);\n this.client = null;\n }\n}\n\n// --- CLI Commands ---\n\n/**\n * Validate command - checks if agent.ts exports correctly\n */\nasync function validateCommand(): Promise<boolean> {\n const agentPath = findAgentFile();\n\n if (!agentPath) {\n console.error(\"[FLUX] No agent.ts or agent.js found in current directory.\");\n console.error(\"[FLUX] Create an agent.ts file with `export default agent`\");\n return false;\n }\n\n console.log(`[FLUX] Validating ${path.basename(agentPath)}...`);\n const result = await validateAgentFile(agentPath);\n\n if (result.valid) {\n console.log(\"[FLUX] ✓ Agent is valid!\");\n return true;\n } else {\n console.error(`[FLUX] ✗ Validation failed: ${result.error}`);\n return false;\n }\n}\n\n/**\n * Run agent locally (for testing without connecting to bridge)\n * Uses the Rapid TUI chat interface\n */\nasync function runLocal() {\n const agentPath = findAgentFile();\n\n if (!agentPath) {\n console.error(\"[FLUX] No agent.ts or agent.js found in current directory.\");\n console.error(\"[FLUX] Create an agent.ts file with `export default agent`\");\n process.exit(1);\n }\n\n // Validate first\n const validation = await validateAgentFile(agentPath);\n if (!validation.valid) {\n console.error(`[FLUX] Agent validation failed: ${validation.error}`);\n process.exit(1);\n }\n\n // Load the agent\n const agent = await loadAgent(agentPath);\n\n // Start the TUI chat interface\n const chat = renderChatUI();\n\n chat.sendMessage(\"Welcome to Flux! Your agent is loaded. Type a message to test it.\");\n\n chat.onInput(async (input) => {\n chat.sendMessage(\"Thinking...\");\n\n try {\n const response = await agent.invoke({\n message: input,\n userPhoneNumber: \"+1234567890\", // Mock phone number for local testing\n });\n chat.sendMessage(response);\n } catch (error: any) {\n chat.sendMessage(`Error: ${error.message}`);\n }\n });\n\n // Keep the Ink app alive. Press Ctrl+C to exit.\n await new Promise(() => {});\n}\n\n/**\n * Run agent in production mode (connected to bridge)\n */\nasync function runProd() {\n const phoneNumber = await getPhoneNumber();\n const agentPath = findAgentFile();\n\n if (!agentPath) {\n console.error(\"[FLUX] No agent.ts or agent.js found in current directory.\");\n console.error(\"[FLUX] Create an agent.ts file with `export default agent`\");\n process.exit(1);\n }\n\n // Validate first\n const validation = await validateAgentFile(agentPath);\n if (!validation.valid) {\n console.error(`[FLUX] Agent validation failed: ${validation.error}`);\n process.exit(1);\n }\n\n // Load the agent\n console.log(`[FLUX] Loading agent from ${path.basename(agentPath)}...`);\n const agent = await loadAgent(agentPath);\n console.log(\"[FLUX] Agent loaded successfully!\");\n\n // Create client with the user's agent as the message handler\n const flux = new FluxClient(phoneNumber, async (message) => {\n console.log(`[FLUX] Processing message from ${message.userPhoneNumber}: ${message.text}`);\n\n try {\n const response = await agent.invoke({\n message: message.text,\n userPhoneNumber: message.userPhoneNumber,\n imageBase64: message.imageBase64,\n });\n console.log(`[FLUX] Agent response: ${response}`);\n return response;\n } catch (error: any) {\n console.error(`[FLUX] Agent error: ${error.message}`);\n return \"Sorry, I encountered an error processing your message.\";\n }\n });\n\n // Connect and register\n await flux.connect();\n await flux.register();\n\n console.log(\"[FLUX] Agent running in production mode. Press Ctrl+C to stop.\");\n console.log(`[FLUX] Messages to ${phoneNumber} will be processed by your agent.\\n`);\n\n // Handle shutdown\n process.on(\"SIGINT\", async () => {\n console.log(\"\\n[FLUX] Shutting down...\");\n await flux.disconnect();\n process.exit(0);\n });\n\n // Keep alive\n await new Promise(() => {});\n}\n\nasync function main() {\n const command = process.argv[2];\n const flag = process.argv[3];\n\n switch (command) {\n case \"login\":\n await login();\n break;\n case \"logout\":\n logout();\n break;\n case \"run\":\n if (flag === \"--local\") {\n await runLocal();\n } else if (flag === \"--prod\" || !flag) {\n // Default to prod mode\n await runProd();\n } else {\n console.error(`[FLUX] Unknown flag: ${flag}`);\n console.log(\"Usage: flux run [--local | --prod]\");\n }\n break;\n case \"validate\":\n await validateCommand();\n break;\n case \"whoami\":\n const config = loadConfig();\n if (config.phoneNumber) {\n console.log(`[FLUX] Logged in as ${config.phoneNumber}`);\n } else {\n console.log(\"[FLUX] Not logged in.\");\n }\n break;\n default:\n console.log(\"Flux CLI - Connect LangChain agents to iMessage\\n\");\n console.log(\"Commands:\");\n console.log(\" flux login - Log in with your phone number\");\n console.log(\" flux logout - Log out\");\n console.log(\" flux validate - Check if agent.ts exports correctly\");\n console.log(\" flux run --local - Test agent locally (no server connection)\");\n console.log(\" flux run --prod - Run agent connected to bridge (default)\");\n console.log(\" flux whoami - Show current logged in user\");\n break;\n }\n}\n\nmain().catch(console.error);"]}
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Service, server, bidi, client, createGrpcClient } from 'better-grpc';
|
|
3
|
+
import { renderChatUI } from '@photon-ai/rapid/cli-chat';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as readline from 'readline';
|
|
7
|
+
import { pathToFileURL } from 'url';
|
|
8
|
+
|
|
9
|
+
var GRPC_SERVER_ADDRESS = process.env.FLUX_SERVER_ADDRESS || "localhost:50051";
|
|
10
|
+
var CONFIG_DIR = path.join(process.env.HOME || "~", ".flux");
|
|
11
|
+
var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
12
|
+
var AGENT_FILE_NAME = "agent.ts";
|
|
13
|
+
function loadConfig() {
|
|
14
|
+
try {
|
|
15
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
16
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
|
|
17
|
+
}
|
|
18
|
+
} catch {
|
|
19
|
+
}
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
function saveConfig(config) {
|
|
23
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
24
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
27
|
+
}
|
|
28
|
+
function clearConfig() {
|
|
29
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
30
|
+
fs.unlinkSync(CONFIG_FILE);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function prompt(question) {
|
|
34
|
+
const rl = readline.createInterface({
|
|
35
|
+
input: process.stdin,
|
|
36
|
+
output: process.stdout
|
|
37
|
+
});
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
rl.question(question, (answer) => {
|
|
40
|
+
rl.close();
|
|
41
|
+
resolve(answer.trim());
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async function login() {
|
|
46
|
+
const phoneNumber = await prompt("Enter your phone number (e.g. +15551234567): ");
|
|
47
|
+
if (!phoneNumber.match(/^\+?[0-9]{10,15}$/)) {
|
|
48
|
+
console.error("Invalid phone number format.");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
console.log("[FLUX] Validating with server...");
|
|
52
|
+
try {
|
|
53
|
+
const clientImpl = FluxService.Client({
|
|
54
|
+
async onIncomingMessage() {
|
|
55
|
+
return { received: true };
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
const client2 = await createGrpcClient(GRPC_SERVER_ADDRESS, clientImpl);
|
|
59
|
+
const result = await client2.FluxService.validateUser(phoneNumber);
|
|
60
|
+
if (result.error) {
|
|
61
|
+
console.error(`[FLUX] Login failed: ${result.error}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
if (result.created) {
|
|
65
|
+
console.log(`[FLUX] New account created for ${phoneNumber}`);
|
|
66
|
+
} else if (result.exists) {
|
|
67
|
+
console.log(`[FLUX] Welcome back, ${phoneNumber}`);
|
|
68
|
+
}
|
|
69
|
+
saveConfig({ phoneNumber });
|
|
70
|
+
console.log(`[FLUX] Logged in as ${phoneNumber}`);
|
|
71
|
+
return phoneNumber;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(`[FLUX] Failed to connect to server: ${error.message}`);
|
|
74
|
+
console.error(`[FLUX] Make sure the Flux server is running at ${GRPC_SERVER_ADDRESS}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function logout() {
|
|
79
|
+
clearConfig();
|
|
80
|
+
console.log("[FLUX] Logged out.");
|
|
81
|
+
}
|
|
82
|
+
async function getPhoneNumber() {
|
|
83
|
+
const config = loadConfig();
|
|
84
|
+
if (config.phoneNumber) {
|
|
85
|
+
return config.phoneNumber;
|
|
86
|
+
}
|
|
87
|
+
console.log("[FLUX] Not logged in.");
|
|
88
|
+
return await login();
|
|
89
|
+
}
|
|
90
|
+
function findAgentFile() {
|
|
91
|
+
const cwd = process.cwd();
|
|
92
|
+
const agentPath = path.join(cwd, AGENT_FILE_NAME);
|
|
93
|
+
if (fs.existsSync(agentPath)) {
|
|
94
|
+
return agentPath;
|
|
95
|
+
}
|
|
96
|
+
const jsPath = path.join(cwd, "agent.js");
|
|
97
|
+
if (fs.existsSync(jsPath)) {
|
|
98
|
+
return jsPath;
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
async function validateAgentFile(agentPath) {
|
|
103
|
+
try {
|
|
104
|
+
const moduleUrl = pathToFileURL(agentPath).href;
|
|
105
|
+
const agentModule = await import(moduleUrl);
|
|
106
|
+
if (!agentModule.default) {
|
|
107
|
+
return { valid: false, error: "No default export found. Use `export default agent`" };
|
|
108
|
+
}
|
|
109
|
+
const agent = agentModule.default;
|
|
110
|
+
if (typeof agent.invoke !== "function") {
|
|
111
|
+
return { valid: false, error: "Agent must have an `invoke` method" };
|
|
112
|
+
}
|
|
113
|
+
return { valid: true };
|
|
114
|
+
} catch (error) {
|
|
115
|
+
return { valid: false, error: `Failed to load agent: ${error.message}` };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function loadAgent(agentPath) {
|
|
119
|
+
const moduleUrl = pathToFileURL(agentPath).href;
|
|
120
|
+
const agentModule = await import(moduleUrl);
|
|
121
|
+
return agentModule.default;
|
|
122
|
+
}
|
|
123
|
+
var FluxService = class extends Service("FluxService") {
|
|
124
|
+
sendMessage = server();
|
|
125
|
+
messageStream = bidi();
|
|
126
|
+
registerAgent = server();
|
|
127
|
+
unregisterAgent = server();
|
|
128
|
+
onIncomingMessage = client();
|
|
129
|
+
// Login validation - checks if user exists in Firebase
|
|
130
|
+
validateUser = server();
|
|
131
|
+
};
|
|
132
|
+
var FluxClient = class {
|
|
133
|
+
client = null;
|
|
134
|
+
phoneNumber;
|
|
135
|
+
onMessage;
|
|
136
|
+
constructor(phoneNumber, onMessage) {
|
|
137
|
+
this.phoneNumber = phoneNumber.replace(/[\s\-\(\)]/g, "");
|
|
138
|
+
this.onMessage = onMessage;
|
|
139
|
+
}
|
|
140
|
+
async connect() {
|
|
141
|
+
const clientImpl = FluxService.Client({
|
|
142
|
+
async onIncomingMessage(message) {
|
|
143
|
+
return { received: true };
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
this.client = await createGrpcClient(GRPC_SERVER_ADDRESS, clientImpl);
|
|
147
|
+
console.log(`[FLUX] Connected to server at ${GRPC_SERVER_ADDRESS}`);
|
|
148
|
+
}
|
|
149
|
+
async register() {
|
|
150
|
+
if (!this.client) throw new Error("Not connected. Call connect() first.");
|
|
151
|
+
const result = await this.client.FluxService.registerAgent(this.phoneNumber);
|
|
152
|
+
if (result.success) {
|
|
153
|
+
console.log(`[FLUX] Registered agent for ${this.phoneNumber}`);
|
|
154
|
+
this.startMessageStream();
|
|
155
|
+
} else {
|
|
156
|
+
console.error(`[FLUX] Registration failed: ${result.error}`);
|
|
157
|
+
}
|
|
158
|
+
return result.success;
|
|
159
|
+
}
|
|
160
|
+
async startMessageStream() {
|
|
161
|
+
if (!this.client) return;
|
|
162
|
+
(async () => {
|
|
163
|
+
for await (const [message] of this.client.FluxService.messageStream) {
|
|
164
|
+
if ("ack" in message) {
|
|
165
|
+
console.log(`[FLUX] Received ack: ${message.ack}`);
|
|
166
|
+
} else {
|
|
167
|
+
console.log(`[FLUX] Incoming message from ${message.userPhoneNumber}: ${message.text}`);
|
|
168
|
+
await this.client.FluxService.messageStream({ ack: message.messageGuid });
|
|
169
|
+
const response = await this.onMessage(message);
|
|
170
|
+
if (response) {
|
|
171
|
+
await this.sendMessage(message.userPhoneNumber, response, message.chatGuid);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
})();
|
|
176
|
+
}
|
|
177
|
+
async sendMessage(to, text, chatGuid) {
|
|
178
|
+
if (!this.client) throw new Error("Not connected. Call connect() first.");
|
|
179
|
+
const result = await this.client.FluxService.sendMessage({
|
|
180
|
+
userPhoneNumber: to,
|
|
181
|
+
text,
|
|
182
|
+
chatGuid
|
|
183
|
+
});
|
|
184
|
+
if (!result.success) {
|
|
185
|
+
console.error(`[FLUX] Send failed: ${result.error}`);
|
|
186
|
+
}
|
|
187
|
+
return result.success;
|
|
188
|
+
}
|
|
189
|
+
async disconnect() {
|
|
190
|
+
if (!this.client) return;
|
|
191
|
+
await this.client.FluxService.unregisterAgent(this.phoneNumber);
|
|
192
|
+
console.log(`[FLUX] Unregistered agent for ${this.phoneNumber}`);
|
|
193
|
+
this.client = null;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
async function validateCommand() {
|
|
197
|
+
const agentPath = findAgentFile();
|
|
198
|
+
if (!agentPath) {
|
|
199
|
+
console.error("[FLUX] No agent.ts or agent.js found in current directory.");
|
|
200
|
+
console.error("[FLUX] Create an agent.ts file with `export default agent`");
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
console.log(`[FLUX] Validating ${path.basename(agentPath)}...`);
|
|
204
|
+
const result = await validateAgentFile(agentPath);
|
|
205
|
+
if (result.valid) {
|
|
206
|
+
console.log("[FLUX] \u2713 Agent is valid!");
|
|
207
|
+
return true;
|
|
208
|
+
} else {
|
|
209
|
+
console.error(`[FLUX] \u2717 Validation failed: ${result.error}`);
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function runLocal() {
|
|
214
|
+
const agentPath = findAgentFile();
|
|
215
|
+
if (!agentPath) {
|
|
216
|
+
console.error("[FLUX] No agent.ts or agent.js found in current directory.");
|
|
217
|
+
console.error("[FLUX] Create an agent.ts file with `export default agent`");
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
const validation = await validateAgentFile(agentPath);
|
|
221
|
+
if (!validation.valid) {
|
|
222
|
+
console.error(`[FLUX] Agent validation failed: ${validation.error}`);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
const agent = await loadAgent(agentPath);
|
|
226
|
+
const chat = renderChatUI();
|
|
227
|
+
chat.sendMessage("Welcome to Flux! Your agent is loaded. Type a message to test it.");
|
|
228
|
+
chat.onInput(async (input) => {
|
|
229
|
+
chat.sendMessage("Thinking...");
|
|
230
|
+
try {
|
|
231
|
+
const response = await agent.invoke({
|
|
232
|
+
message: input,
|
|
233
|
+
userPhoneNumber: "+1234567890"
|
|
234
|
+
// Mock phone number for local testing
|
|
235
|
+
});
|
|
236
|
+
chat.sendMessage(response);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
chat.sendMessage(`Error: ${error.message}`);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
await new Promise(() => {
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
async function runProd() {
|
|
245
|
+
const phoneNumber = await getPhoneNumber();
|
|
246
|
+
const agentPath = findAgentFile();
|
|
247
|
+
if (!agentPath) {
|
|
248
|
+
console.error("[FLUX] No agent.ts or agent.js found in current directory.");
|
|
249
|
+
console.error("[FLUX] Create an agent.ts file with `export default agent`");
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
const validation = await validateAgentFile(agentPath);
|
|
253
|
+
if (!validation.valid) {
|
|
254
|
+
console.error(`[FLUX] Agent validation failed: ${validation.error}`);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
console.log(`[FLUX] Loading agent from ${path.basename(agentPath)}...`);
|
|
258
|
+
const agent = await loadAgent(agentPath);
|
|
259
|
+
console.log("[FLUX] Agent loaded successfully!");
|
|
260
|
+
const flux = new FluxClient(phoneNumber, async (message) => {
|
|
261
|
+
console.log(`[FLUX] Processing message from ${message.userPhoneNumber}: ${message.text}`);
|
|
262
|
+
try {
|
|
263
|
+
const response = await agent.invoke({
|
|
264
|
+
message: message.text,
|
|
265
|
+
userPhoneNumber: message.userPhoneNumber,
|
|
266
|
+
imageBase64: message.imageBase64
|
|
267
|
+
});
|
|
268
|
+
console.log(`[FLUX] Agent response: ${response}`);
|
|
269
|
+
return response;
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.error(`[FLUX] Agent error: ${error.message}`);
|
|
272
|
+
return "Sorry, I encountered an error processing your message.";
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
await flux.connect();
|
|
276
|
+
await flux.register();
|
|
277
|
+
console.log("[FLUX] Agent running in production mode. Press Ctrl+C to stop.");
|
|
278
|
+
console.log(`[FLUX] Messages to ${phoneNumber} will be processed by your agent.
|
|
279
|
+
`);
|
|
280
|
+
process.on("SIGINT", async () => {
|
|
281
|
+
console.log("\n[FLUX] Shutting down...");
|
|
282
|
+
await flux.disconnect();
|
|
283
|
+
process.exit(0);
|
|
284
|
+
});
|
|
285
|
+
await new Promise(() => {
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
async function main() {
|
|
289
|
+
const command = process.argv[2];
|
|
290
|
+
const flag = process.argv[3];
|
|
291
|
+
switch (command) {
|
|
292
|
+
case "login":
|
|
293
|
+
await login();
|
|
294
|
+
break;
|
|
295
|
+
case "logout":
|
|
296
|
+
logout();
|
|
297
|
+
break;
|
|
298
|
+
case "run":
|
|
299
|
+
if (flag === "--local") {
|
|
300
|
+
await runLocal();
|
|
301
|
+
} else if (flag === "--prod" || !flag) {
|
|
302
|
+
await runProd();
|
|
303
|
+
} else {
|
|
304
|
+
console.error(`[FLUX] Unknown flag: ${flag}`);
|
|
305
|
+
console.log("Usage: flux run [--local | --prod]");
|
|
306
|
+
}
|
|
307
|
+
break;
|
|
308
|
+
case "validate":
|
|
309
|
+
await validateCommand();
|
|
310
|
+
break;
|
|
311
|
+
case "whoami":
|
|
312
|
+
const config = loadConfig();
|
|
313
|
+
if (config.phoneNumber) {
|
|
314
|
+
console.log(`[FLUX] Logged in as ${config.phoneNumber}`);
|
|
315
|
+
} else {
|
|
316
|
+
console.log("[FLUX] Not logged in.");
|
|
317
|
+
}
|
|
318
|
+
break;
|
|
319
|
+
default:
|
|
320
|
+
console.log("Flux CLI - Connect LangChain agents to iMessage\n");
|
|
321
|
+
console.log("Commands:");
|
|
322
|
+
console.log(" flux login - Log in with your phone number");
|
|
323
|
+
console.log(" flux logout - Log out");
|
|
324
|
+
console.log(" flux validate - Check if agent.ts exports correctly");
|
|
325
|
+
console.log(" flux run --local - Test agent locally (no server connection)");
|
|
326
|
+
console.log(" flux run --prod - Run agent connected to bridge (default)");
|
|
327
|
+
console.log(" flux whoami - Show current logged in user");
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
main().catch(console.error);
|
|
332
|
+
|
|
333
|
+
export { FluxClient };
|
|
334
|
+
//# sourceMappingURL=cli.mjs.map
|
|
335
|
+
//# sourceMappingURL=cli.mjs.map
|
package/dist/cli.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"names":["client"],"mappings":";;;;;;;;AAeA,IAAM,mBAAA,GAAsB,OAAA,CAAQ,GAAA,CAAI,mBAAA,IAAuB,iBAAA;AAC/D,IAAM,aAAkB,IAAA,CAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAA,IAAQ,KAAK,OAAO,CAAA;AAC7D,IAAM,WAAA,GAAmB,IAAA,CAAA,IAAA,CAAK,UAAA,EAAY,aAAa,CAAA;AACvD,IAAM,eAAA,GAAkB,UAAA;AAQxB,SAAS,UAAA,GAAyB;AAChC,EAAA,IAAI;AACF,IAAA,IAAO,EAAA,CAAA,UAAA,CAAW,WAAW,CAAA,EAAG;AAC9B,MAAA,OAAO,IAAA,CAAK,KAAA,CAAS,EAAA,CAAA,YAAA,CAAa,WAAA,EAAa,OAAO,CAAC,CAAA;AAAA,IACzD;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAAC;AACT,EAAA,OAAO,EAAC;AACV;AAEA,SAAS,WAAW,MAAA,EAA0B;AAC5C,EAAA,IAAI,CAAI,EAAA,CAAA,UAAA,CAAW,UAAU,CAAA,EAAG;AAC9B,IAAG,EAAA,CAAA,SAAA,CAAU,UAAA,EAAY,EAAE,SAAA,EAAW,MAAM,CAAA;AAAA,EAC9C;AACA,EAAG,iBAAc,WAAA,EAAa,IAAA,CAAK,UAAU,MAAA,EAAQ,IAAA,EAAM,CAAC,CAAC,CAAA;AAC/D;AAEA,SAAS,WAAA,GAAoB;AAC3B,EAAA,IAAO,EAAA,CAAA,UAAA,CAAW,WAAW,CAAA,EAAG;AAC9B,IAAG,cAAW,WAAW,CAAA;AAAA,EAC3B;AACF;AAEA,eAAe,OAAO,QAAA,EAAmC;AACvD,EAAA,MAAM,KAAc,QAAA,CAAA,eAAA,CAAgB;AAAA,IAClC,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,QAAQ,OAAA,CAAQ;AAAA,GACjB,CAAA;AACD,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,IAAA,EAAA,CAAG,QAAA,CAAS,QAAA,EAAU,CAAC,MAAA,KAAW;AAChC,MAAA,EAAA,CAAG,KAAA,EAAM;AACT,MAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA;AAAA,IACvB,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH;AAEA,eAAe,KAAA,GAAyB;AACtC,EAAA,MAAM,WAAA,GAAc,MAAM,MAAA,CAAO,+CAA+C,CAAA;AAChF,EAAA,IAAI,CAAC,WAAA,CAAY,KAAA,CAAM,mBAAmB,CAAA,EAAG;AAC3C,IAAA,OAAA,CAAQ,MAAM,8BAA8B,CAAA;AAC5C,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,OAAA,CAAQ,IAAI,kCAAkC,CAAA;AAC9C,EAAA,IAAI;AACF,IAAA,MAAM,UAAA,GAAa,YAAY,MAAA,CAAO;AAAA,MACpC,MAAM,iBAAA,GAAoB;AACxB,QAAA,OAAO,EAAE,UAAU,IAAA,EAAK;AAAA,MAC1B;AAAA,KACD,CAAA;AACD,IAAA,MAAMA,OAAAA,GAAS,MAAM,gBAAA,CAAiB,mBAAA,EAAqB,UAAU,CAAA;AACrE,IAAA,MAAM,MAAA,GAAS,MAAMA,OAAAA,CAAO,WAAA,CAAY,aAAa,WAAW,CAAA;AAEhE,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,qBAAA,EAAwB,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AACpD,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB;AAEA,IAAA,IAAI,OAAO,OAAA,EAAS;AAClB,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,+BAAA,EAAkC,WAAW,CAAA,CAAE,CAAA;AAAA,IAC7D,CAAA,MAAA,IAAW,OAAO,MAAA,EAAQ;AACxB,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,qBAAA,EAAwB,WAAW,CAAA,CAAE,CAAA;AAAA,IACnD;AAEA,IAAA,UAAA,CAAW,EAAE,aAAa,CAAA;AAC1B,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,oBAAA,EAAuB,WAAW,CAAA,CAAE,CAAA;AAChD,IAAA,OAAO,WAAA;AAAA,EACT,SAAS,KAAA,EAAY;AACnB,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,oCAAA,EAAuC,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AACpE,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,+CAAA,EAAkD,mBAAmB,CAAA,CAAE,CAAA;AACrF,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACF;AAEA,SAAS,MAAA,GAAe;AACtB,EAAA,WAAA,EAAY;AACZ,EAAA,OAAA,CAAQ,IAAI,oBAAoB,CAAA;AAClC;AAEA,eAAe,cAAA,GAAkC;AAC/C,EAAA,MAAM,SAAS,UAAA,EAAW;AAC1B,EAAA,IAAI,OAAO,WAAA,EAAa;AACtB,IAAA,OAAO,MAAA,CAAO,WAAA;AAAA,EAChB;AACA,EAAA,OAAA,CAAQ,IAAI,uBAAuB,CAAA;AACnC,EAAA,OAAO,MAAM,KAAA,EAAM;AACrB;AAiBA,SAAS,aAAA,GAA+B;AACtC,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,EAAI;AACxB,EAAA,MAAM,SAAA,GAAiB,IAAA,CAAA,IAAA,CAAK,GAAA,EAAK,eAAe,CAAA;AAEhD,EAAA,IAAO,EAAA,CAAA,UAAA,CAAW,SAAS,CAAA,EAAG;AAC5B,IAAA,OAAO,SAAA;AAAA,EACT;AAGA,EAAA,MAAM,MAAA,GAAc,IAAA,CAAA,IAAA,CAAK,GAAA,EAAK,UAAU,CAAA;AACxC,EAAA,IAAO,EAAA,CAAA,UAAA,CAAW,MAAM,CAAA,EAAG;AACzB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA;AACT;AAKA,eAAe,kBAAkB,SAAA,EAAgE;AAC/F,EAAA,IAAI;AACF,IAAA,MAAM,SAAA,GAAY,aAAA,CAAc,SAAS,CAAA,CAAE,IAAA;AAC3C,IAAA,MAAM,WAAA,GAAc,MAAM,OAAO,SAAA,CAAA;AAEjC,IAAA,IAAI,CAAC,YAAY,OAAA,EAAS;AACxB,MAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,qDAAA,EAAsD;AAAA,IACtF;AAEA,IAAA,MAAM,QAAQ,WAAA,CAAY,OAAA;AAE1B,IAAA,IAAI,OAAO,KAAA,CAAM,MAAA,KAAW,UAAA,EAAY;AACtC,MAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,oCAAA,EAAqC;AAAA,IACrE;AAEA,IAAA,OAAO,EAAE,OAAO,IAAA,EAAK;AAAA,EACvB,SAAS,KAAA,EAAY;AACnB,IAAA,OAAO,EAAE,KAAA,EAAO,KAAA,EAAO,OAAO,CAAA,sBAAA,EAAyB,KAAA,CAAM,OAAO,CAAA,CAAA,EAAG;AAAA,EACzE;AACF;AAKA,eAAe,UAAU,SAAA,EAAuC;AAC9D,EAAA,MAAM,SAAA,GAAY,aAAA,CAAc,SAAS,CAAA,CAAE,IAAA;AAC3C,EAAA,MAAM,WAAA,GAAc,MAAM,OAAO,SAAA,CAAA;AACjC,EAAA,OAAO,WAAA,CAAY,OAAA;AACrB;AAoBA,IAAe,WAAA,GAAf,cAAmC,OAAA,CAAQ,aAAa,CAAA,CAAE;AAAA,EACxD,cAAc,MAAA,EAA2E;AAAA,EACzF,gBAAgB,IAAA,EAA2D;AAAA,EAC3E,gBAAgB,MAAA,EAAsE;AAAA,EACtF,kBAAkB,MAAA,EAAsD;AAAA,EACxE,oBAAoB,MAAA,EAA4D;AAAA;AAAA,EAEhF,eAAe,MAAA,EAAuF;AACxG,CAAA;AAIO,IAAM,aAAN,MAAiB;AAAA,EACd,MAAA,GAA8D,IAAA;AAAA,EAC9D,WAAA;AAAA,EACA,SAAA;AAAA,EAER,WAAA,CACE,aACA,SAAA,EACA;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,WAAA,CAAY,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AACxD,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAAA,EACnB;AAAA,EAEA,MAAM,OAAA,GAAyB;AAC7B,IAAA,MAAM,UAAA,GAAa,YAAY,MAAA,CAAO;AAAA,MACpC,MAAM,kBAAkB,OAAA,EAA0B;AAChD,QAAA,OAAO,EAAE,UAAU,IAAA,EAAK;AAAA,MAC1B;AAAA,KACD,CAAA;AAED,IAAA,IAAA,CAAK,MAAA,GAAS,MAAM,gBAAA,CAAiB,mBAAA,EAAqB,UAAU,CAAA;AACpE,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,8BAAA,EAAiC,mBAAmB,CAAA,CAAE,CAAA;AAAA,EACpE;AAAA,EAEA,MAAM,QAAA,GAA6B;AACjC,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,MAAM,IAAI,MAAM,sCAAsC,CAAA;AAExE,IAAA,MAAM,SAAS,MAAM,IAAA,CAAK,OAAO,WAAA,CAAY,aAAA,CAAc,KAAK,WAAW,CAAA;AAC3E,IAAA,IAAI,OAAO,OAAA,EAAS;AAClB,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,4BAAA,EAA+B,IAAA,CAAK,WAAW,CAAA,CAAE,CAAA;AAC7D,MAAA,IAAA,CAAK,kBAAA,EAAmB;AAAA,IAC1B,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,4BAAA,EAA+B,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IAC7D;AACA,IAAA,OAAO,MAAA,CAAO,OAAA;AAAA,EAChB;AAAA,EAEA,MAAc,kBAAA,GAAoC;AAChD,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAElB,IAAA,CAAC,YAAY;AACX,MAAA,WAAA,MAAiB,CAAC,OAAO,CAAA,IAAK,IAAA,CAAK,MAAA,CAAQ,YAAY,aAAA,EAAe;AACpE,QAAA,IAAI,SAAS,OAAA,EAAS;AACpB,UAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,qBAAA,EAAwB,OAAA,CAAQ,GAAG,CAAA,CAAE,CAAA;AAAA,QACnD,CAAA,MAAO;AACL,UAAA,OAAA,CAAQ,IAAI,CAAA,6BAAA,EAAgC,OAAA,CAAQ,eAAe,CAAA,EAAA,EAAK,OAAA,CAAQ,IAAI,CAAA,CAAE,CAAA;AAGtF,UAAA,MAAM,IAAA,CAAK,OAAQ,WAAA,CAAY,aAAA,CAAc,EAAE,GAAA,EAAK,OAAA,CAAQ,aAAa,CAAA;AAGzE,UAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA;AAG7C,UAAA,IAAI,QAAA,EAAU;AACZ,YAAA,MAAM,KAAK,WAAA,CAAY,OAAA,CAAQ,eAAA,EAAiB,QAAA,EAAU,QAAQ,QAAQ,CAAA;AAAA,UAC5E;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA,GAAG;AAAA,EACL;AAAA,EAEA,MAAM,WAAA,CAAY,EAAA,EAAY,IAAA,EAAc,QAAA,EAAqC;AAC/E,IAAA,IAAI,CAAC,IAAA,CAAK,MAAA,EAAQ,MAAM,IAAI,MAAM,sCAAsC,CAAA;AAExE,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,MAAA,CAAO,YAAY,WAAA,CAAY;AAAA,MACvD,eAAA,EAAiB,EAAA;AAAA,MACjB,IAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,MAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,oBAAA,EAAuB,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IACrD;AACA,IAAA,OAAO,MAAA,CAAO,OAAA;AAAA,EAChB;AAAA,EAEA,MAAM,UAAA,GAA4B;AAChC,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAElB,IAAA,MAAM,IAAA,CAAK,MAAA,CAAO,WAAA,CAAY,eAAA,CAAgB,KAAK,WAAW,CAAA;AAC9D,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,8BAAA,EAAiC,IAAA,CAAK,WAAW,CAAA,CAAE,CAAA;AAC/D,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AAAA,EAChB;AACF;AAOA,eAAe,eAAA,GAAoC;AACjD,EAAA,MAAM,YAAY,aAAA,EAAc;AAEhC,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAA,CAAQ,MAAM,4DAA4D,CAAA;AAC1E,IAAA,OAAA,CAAQ,MAAM,4DAA4D,CAAA;AAC1E,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,kBAAA,EAA0B,IAAA,CAAA,QAAA,CAAS,SAAS,CAAC,CAAA,GAAA,CAAK,CAAA;AAC9D,EAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB,SAAS,CAAA;AAEhD,EAAA,IAAI,OAAO,KAAA,EAAO;AAChB,IAAA,OAAA,CAAQ,IAAI,+BAA0B,CAAA;AACtC,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,MAAO;AACL,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,iCAAA,EAA+B,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAC3D,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAMA,eAAe,QAAA,GAAW;AACxB,EAAA,MAAM,YAAY,aAAA,EAAc;AAEhC,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAA,CAAQ,MAAM,4DAA4D,CAAA;AAC1E,IAAA,OAAA,CAAQ,MAAM,4DAA4D,CAAA;AAC1E,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,MAAM,UAAA,GAAa,MAAM,iBAAA,CAAkB,SAAS,CAAA;AACpD,EAAA,IAAI,CAAC,WAAW,KAAA,EAAO;AACrB,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,gCAAA,EAAmC,UAAA,CAAW,KAAK,CAAA,CAAE,CAAA;AACnE,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,CAAU,SAAS,CAAA;AAGvC,EAAA,MAAM,OAAO,YAAA,EAAa;AAE1B,EAAA,IAAA,CAAK,YAAY,mEAAmE,CAAA;AAEpF,EAAA,IAAA,CAAK,OAAA,CAAQ,OAAO,KAAA,KAAU;AAC5B,IAAA,IAAA,CAAK,YAAY,aAAa,CAAA;AAE9B,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,MAAA,CAAO;AAAA,QAClC,OAAA,EAAS,KAAA;AAAA,QACT,eAAA,EAAiB;AAAA;AAAA,OAClB,CAAA;AACD,MAAA,IAAA,CAAK,YAAY,QAAQ,CAAA;AAAA,IAC3B,SAAS,KAAA,EAAY;AACnB,MAAA,IAAA,CAAK,WAAA,CAAY,CAAA,OAAA,EAAU,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA,IAC5C;AAAA,EACF,CAAC,CAAA;AAGD,EAAA,MAAM,IAAI,QAAQ,MAAM;AAAA,EAAC,CAAC,CAAA;AAC5B;AAKA,eAAe,OAAA,GAAU;AACvB,EAAA,MAAM,WAAA,GAAc,MAAM,cAAA,EAAe;AACzC,EAAA,MAAM,YAAY,aAAA,EAAc;AAEhC,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAA,CAAQ,MAAM,4DAA4D,CAAA;AAC1E,IAAA,OAAA,CAAQ,MAAM,4DAA4D,CAAA;AAC1E,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,MAAM,UAAA,GAAa,MAAM,iBAAA,CAAkB,SAAS,CAAA;AACpD,EAAA,IAAI,CAAC,WAAW,KAAA,EAAO;AACrB,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,gCAAA,EAAmC,UAAA,CAAW,KAAK,CAAA,CAAE,CAAA;AACnE,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,0BAAA,EAAkC,IAAA,CAAA,QAAA,CAAS,SAAS,CAAC,CAAA,GAAA,CAAK,CAAA;AACtE,EAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,CAAU,SAAS,CAAA;AACvC,EAAA,OAAA,CAAQ,IAAI,mCAAmC,CAAA;AAG/C,EAAA,MAAM,IAAA,GAAO,IAAI,UAAA,CAAW,WAAA,EAAa,OAAO,OAAA,KAAY;AAC1D,IAAA,OAAA,CAAQ,IAAI,CAAA,+BAAA,EAAkC,OAAA,CAAQ,eAAe,CAAA,EAAA,EAAK,OAAA,CAAQ,IAAI,CAAA,CAAE,CAAA;AAExF,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,MAAA,CAAO;AAAA,QAClC,SAAS,OAAA,CAAQ,IAAA;AAAA,QACjB,iBAAiB,OAAA,CAAQ,eAAA;AAAA,QACzB,aAAa,OAAA,CAAQ;AAAA,OACtB,CAAA;AACD,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,uBAAA,EAA0B,QAAQ,CAAA,CAAE,CAAA;AAChD,MAAA,OAAO,QAAA;AAAA,IACT,SAAS,KAAA,EAAY;AACnB,MAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,oBAAA,EAAuB,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AACpD,MAAA,OAAO,wDAAA;AAAA,IACT;AAAA,EACF,CAAC,CAAA;AAGD,EAAA,MAAM,KAAK,OAAA,EAAQ;AACnB,EAAA,MAAM,KAAK,QAAA,EAAS;AAEpB,EAAA,OAAA,CAAQ,IAAI,gEAAgE,CAAA;AAC5E,EAAA,OAAA,CAAQ,GAAA,CAAI,sBAAsB,WAAW,CAAA;AAAA,CAAqC,CAAA;AAGlF,EAAA,OAAA,CAAQ,EAAA,CAAG,UAAU,YAAY;AAC/B,IAAA,OAAA,CAAQ,IAAI,2BAA2B,CAAA;AACvC,IAAA,MAAM,KAAK,UAAA,EAAW;AACtB,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB,CAAC,CAAA;AAGD,EAAA,MAAM,IAAI,QAAQ,MAAM;AAAA,EAAC,CAAC,CAAA;AAC5B;AAEA,eAAe,IAAA,GAAO;AACpB,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA;AAC9B,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA;AAE3B,EAAA,QAAQ,OAAA;AAAS,IACf,KAAK,OAAA;AACH,MAAA,MAAM,KAAA,EAAM;AACZ,MAAA;AAAA,IACF,KAAK,QAAA;AACH,MAAA,MAAA,EAAO;AACP,MAAA;AAAA,IACF,KAAK,KAAA;AACH,MAAA,IAAI,SAAS,SAAA,EAAW;AACtB,QAAA,MAAM,QAAA,EAAS;AAAA,MACjB,CAAA,MAAA,IAAW,IAAA,KAAS,QAAA,IAAY,CAAC,IAAA,EAAM;AAErC,QAAA,MAAM,OAAA,EAAQ;AAAA,MAChB,CAAA,MAAO;AACL,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,qBAAA,EAAwB,IAAI,CAAA,CAAE,CAAA;AAC5C,QAAA,OAAA,CAAQ,IAAI,oCAAoC,CAAA;AAAA,MAClD;AACA,MAAA;AAAA,IACF,KAAK,UAAA;AACH,MAAA,MAAM,eAAA,EAAgB;AACtB,MAAA;AAAA,IACF,KAAK,QAAA;AACH,MAAA,MAAM,SAAS,UAAA,EAAW;AAC1B,MAAA,IAAI,OAAO,WAAA,EAAa;AACtB,QAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,oBAAA,EAAuB,MAAA,CAAO,WAAW,CAAA,CAAE,CAAA;AAAA,MACzD,CAAA,MAAO;AACL,QAAA,OAAA,CAAQ,IAAI,uBAAuB,CAAA;AAAA,MACrC;AACA,MAAA;AAAA,IACF;AACE,MAAA,OAAA,CAAQ,IAAI,mDAAmD,CAAA;AAC/D,MAAA,OAAA,CAAQ,IAAI,WAAW,CAAA;AACvB,MAAA,OAAA,CAAQ,IAAI,uDAAuD,CAAA;AACnE,MAAA,OAAA,CAAQ,IAAI,iCAAiC,CAAA;AAC7C,MAAA,OAAA,CAAQ,IAAI,6DAA6D,CAAA;AACzE,MAAA,OAAA,CAAQ,IAAI,mEAAmE,CAAA;AAC/E,MAAA,OAAA,CAAQ,IAAI,iEAAiE,CAAA;AAC7E,MAAA,OAAA,CAAQ,IAAI,qDAAqD,CAAA;AACjE,MAAA;AAAA;AAEN;AAEA,IAAA,EAAK,CAAE,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA","file":"cli.mjs","sourcesContent":["/**\n * Flux CLI - gRPC Client for iMessage Bridge\n * ==========================================\n * This code connects the Flux CLI to the Flux Server's iMessage bridge.\n * Users define their LangChain agent in agent.ts with `export default agent`\n */\n\nimport { Service, server, client, bidi, createGrpcClient } from \"better-grpc\";\nimport { renderChatUI } from \"@photon-ai/rapid/cli-chat\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as readline from \"readline\";\nimport { pathToFileURL } from \"url\";\n\n// --- Configuration ---\nconst GRPC_SERVER_ADDRESS = process.env.FLUX_SERVER_ADDRESS || \"localhost:50051\";\nconst CONFIG_DIR = path.join(process.env.HOME || \"~\", \".flux\");\nconst CONFIG_FILE = path.join(CONFIG_DIR, \"config.json\");\nconst AGENT_FILE_NAME = \"agent.ts\";\n\n// --- Auth Storage ---\n\ninterface FluxConfig {\n phoneNumber?: string;\n}\n\nfunction loadConfig(): FluxConfig {\n try {\n if (fs.existsSync(CONFIG_FILE)) {\n return JSON.parse(fs.readFileSync(CONFIG_FILE, \"utf-8\"));\n }\n } catch {}\n return {};\n}\n\nfunction saveConfig(config: FluxConfig): void {\n if (!fs.existsSync(CONFIG_DIR)) {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n }\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n}\n\nfunction clearConfig(): void {\n if (fs.existsSync(CONFIG_FILE)) {\n fs.unlinkSync(CONFIG_FILE);\n }\n}\n\nasync function prompt(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nasync function login(): Promise<string> {\n const phoneNumber = await prompt(\"Enter your phone number (e.g. +15551234567): \");\n if (!phoneNumber.match(/^\\+?[0-9]{10,15}$/)) {\n console.error(\"Invalid phone number format.\");\n process.exit(1);\n }\n\n // Validate with server (checks/creates user in Firebase)\n console.log(\"[FLUX] Validating with server...\");\n try {\n const clientImpl = FluxService.Client({\n async onIncomingMessage() {\n return { received: true };\n },\n });\n const client = await createGrpcClient(GRPC_SERVER_ADDRESS, clientImpl);\n const result = await client.FluxService.validateUser(phoneNumber);\n\n if (result.error) {\n console.error(`[FLUX] Login failed: ${result.error}`);\n process.exit(1);\n }\n\n if (result.created) {\n console.log(`[FLUX] New account created for ${phoneNumber}`);\n } else if (result.exists) {\n console.log(`[FLUX] Welcome back, ${phoneNumber}`);\n }\n\n saveConfig({ phoneNumber });\n console.log(`[FLUX] Logged in as ${phoneNumber}`);\n return phoneNumber;\n } catch (error: any) {\n console.error(`[FLUX] Failed to connect to server: ${error.message}`);\n console.error(`[FLUX] Make sure the Flux server is running at ${GRPC_SERVER_ADDRESS}`);\n process.exit(1);\n }\n}\n\nfunction logout(): void {\n clearConfig();\n console.log(\"[FLUX] Logged out.\");\n}\n\nasync function getPhoneNumber(): Promise<string> {\n const config = loadConfig();\n if (config.phoneNumber) {\n return config.phoneNumber;\n }\n console.log(\"[FLUX] Not logged in.\");\n return await login();\n}\n\n// --- Agent Types ---\n\n/**\n * FluxAgent interface - users must export default an object matching this interface\n * The agent receives a message and returns a response string\n */\nexport interface FluxAgent {\n invoke: (input: { message: string; userPhoneNumber: string; imageBase64?: string }) => Promise<string>;\n}\n\n// --- Agent Loader ---\n\n/**\n * Find agent.ts in the current working directory\n */\nfunction findAgentFile(): string | null {\n const cwd = process.cwd();\n const agentPath = path.join(cwd, AGENT_FILE_NAME);\n\n if (fs.existsSync(agentPath)) {\n return agentPath;\n }\n\n // Also check for agent.js\n const jsPath = path.join(cwd, \"agent.js\");\n if (fs.existsSync(jsPath)) {\n return jsPath;\n }\n\n return null;\n}\n\n/**\n * Validate that the agent file exports a default agent with invoke method\n */\nasync function validateAgentFile(agentPath: string): Promise<{ valid: boolean; error?: string }> {\n try {\n const moduleUrl = pathToFileURL(agentPath).href;\n const agentModule = await import(moduleUrl);\n\n if (!agentModule.default) {\n return { valid: false, error: \"No default export found. Use `export default agent`\" };\n }\n\n const agent = agentModule.default;\n\n if (typeof agent.invoke !== \"function\") {\n return { valid: false, error: \"Agent must have an `invoke` method\" };\n }\n\n return { valid: true };\n } catch (error: any) {\n return { valid: false, error: `Failed to load agent: ${error.message}` };\n }\n}\n\n/**\n * Load the agent from agent.ts\n */\nasync function loadAgent(agentPath: string): Promise<FluxAgent> {\n const moduleUrl = pathToFileURL(agentPath).href;\n const agentModule = await import(moduleUrl);\n return agentModule.default as FluxAgent;\n}\n\n// --- Message Types ---\n\nexport interface IncomingMessage {\n userPhoneNumber: string;\n text: string;\n imageBase64?: string;\n chatGuid: string;\n messageGuid: string;\n}\n\nexport interface OutgoingMessage {\n userPhoneNumber: string;\n text: string;\n chatGuid?: string;\n}\n\n// --- FluxService Definition (must match server) ---\n\nabstract class FluxService extends Service(\"FluxService\") {\n sendMessage = server<(message: OutgoingMessage) => { success: boolean; error?: string }>();\n messageStream = bidi<(message: IncomingMessage | { ack: string }) => void>();\n registerAgent = server<(phoneNumber: string) => { success: boolean; error?: string }>();\n unregisterAgent = server<(phoneNumber: string) => { success: boolean }>();\n onIncomingMessage = client<(message: IncomingMessage) => { received: boolean }>();\n // Login validation - checks if user exists in Firebase\n validateUser = server<(phoneNumber: string) => { exists: boolean; created: boolean; error?: string }>();\n}\n\n// --- FluxClient Class ---\n\nexport class FluxClient {\n private client: Awaited<ReturnType<typeof createGrpcClient>> | null = null;\n private phoneNumber: string;\n private onMessage: (message: IncomingMessage) => Promise<string | void>;\n\n constructor(\n phoneNumber: string,\n onMessage: (message: IncomingMessage) => Promise<string | void>\n ) {\n this.phoneNumber = phoneNumber.replace(/[\\s\\-\\(\\)]/g, \"\");\n this.onMessage = onMessage;\n }\n\n async connect(): Promise<void> {\n const clientImpl = FluxService.Client({\n async onIncomingMessage(message: IncomingMessage) {\n return { received: true };\n },\n });\n\n this.client = await createGrpcClient(GRPC_SERVER_ADDRESS, clientImpl);\n console.log(`[FLUX] Connected to server at ${GRPC_SERVER_ADDRESS}`);\n }\n\n async register(): Promise<boolean> {\n if (!this.client) throw new Error(\"Not connected. Call connect() first.\");\n\n const result = await this.client.FluxService.registerAgent(this.phoneNumber);\n if (result.success) {\n console.log(`[FLUX] Registered agent for ${this.phoneNumber}`);\n this.startMessageStream();\n } else {\n console.error(`[FLUX] Registration failed: ${result.error}`);\n }\n return result.success;\n }\n\n private async startMessageStream(): Promise<void> {\n if (!this.client) return;\n\n (async () => {\n for await (const [message] of this.client!.FluxService.messageStream) {\n if (\"ack\" in message) {\n console.log(`[FLUX] Received ack: ${message.ack}`);\n } else {\n console.log(`[FLUX] Incoming message from ${message.userPhoneNumber}: ${message.text}`);\n\n // Acknowledge receipt\n await this.client!.FluxService.messageStream({ ack: message.messageGuid });\n\n // Process with user's agent and get response\n const response = await this.onMessage(message);\n\n // Send response if agent returned one\n if (response) {\n await this.sendMessage(message.userPhoneNumber, response, message.chatGuid);\n }\n }\n }\n })();\n }\n\n async sendMessage(to: string, text: string, chatGuid?: string): Promise<boolean> {\n if (!this.client) throw new Error(\"Not connected. Call connect() first.\");\n\n const result = await this.client.FluxService.sendMessage({\n userPhoneNumber: to,\n text,\n chatGuid,\n });\n\n if (!result.success) {\n console.error(`[FLUX] Send failed: ${result.error}`);\n }\n return result.success;\n }\n\n async disconnect(): Promise<void> {\n if (!this.client) return;\n\n await this.client.FluxService.unregisterAgent(this.phoneNumber);\n console.log(`[FLUX] Unregistered agent for ${this.phoneNumber}`);\n this.client = null;\n }\n}\n\n// --- CLI Commands ---\n\n/**\n * Validate command - checks if agent.ts exports correctly\n */\nasync function validateCommand(): Promise<boolean> {\n const agentPath = findAgentFile();\n\n if (!agentPath) {\n console.error(\"[FLUX] No agent.ts or agent.js found in current directory.\");\n console.error(\"[FLUX] Create an agent.ts file with `export default agent`\");\n return false;\n }\n\n console.log(`[FLUX] Validating ${path.basename(agentPath)}...`);\n const result = await validateAgentFile(agentPath);\n\n if (result.valid) {\n console.log(\"[FLUX] ✓ Agent is valid!\");\n return true;\n } else {\n console.error(`[FLUX] ✗ Validation failed: ${result.error}`);\n return false;\n }\n}\n\n/**\n * Run agent locally (for testing without connecting to bridge)\n * Uses the Rapid TUI chat interface\n */\nasync function runLocal() {\n const agentPath = findAgentFile();\n\n if (!agentPath) {\n console.error(\"[FLUX] No agent.ts or agent.js found in current directory.\");\n console.error(\"[FLUX] Create an agent.ts file with `export default agent`\");\n process.exit(1);\n }\n\n // Validate first\n const validation = await validateAgentFile(agentPath);\n if (!validation.valid) {\n console.error(`[FLUX] Agent validation failed: ${validation.error}`);\n process.exit(1);\n }\n\n // Load the agent\n const agent = await loadAgent(agentPath);\n\n // Start the TUI chat interface\n const chat = renderChatUI();\n\n chat.sendMessage(\"Welcome to Flux! Your agent is loaded. Type a message to test it.\");\n\n chat.onInput(async (input) => {\n chat.sendMessage(\"Thinking...\");\n\n try {\n const response = await agent.invoke({\n message: input,\n userPhoneNumber: \"+1234567890\", // Mock phone number for local testing\n });\n chat.sendMessage(response);\n } catch (error: any) {\n chat.sendMessage(`Error: ${error.message}`);\n }\n });\n\n // Keep the Ink app alive. Press Ctrl+C to exit.\n await new Promise(() => {});\n}\n\n/**\n * Run agent in production mode (connected to bridge)\n */\nasync function runProd() {\n const phoneNumber = await getPhoneNumber();\n const agentPath = findAgentFile();\n\n if (!agentPath) {\n console.error(\"[FLUX] No agent.ts or agent.js found in current directory.\");\n console.error(\"[FLUX] Create an agent.ts file with `export default agent`\");\n process.exit(1);\n }\n\n // Validate first\n const validation = await validateAgentFile(agentPath);\n if (!validation.valid) {\n console.error(`[FLUX] Agent validation failed: ${validation.error}`);\n process.exit(1);\n }\n\n // Load the agent\n console.log(`[FLUX] Loading agent from ${path.basename(agentPath)}...`);\n const agent = await loadAgent(agentPath);\n console.log(\"[FLUX] Agent loaded successfully!\");\n\n // Create client with the user's agent as the message handler\n const flux = new FluxClient(phoneNumber, async (message) => {\n console.log(`[FLUX] Processing message from ${message.userPhoneNumber}: ${message.text}`);\n\n try {\n const response = await agent.invoke({\n message: message.text,\n userPhoneNumber: message.userPhoneNumber,\n imageBase64: message.imageBase64,\n });\n console.log(`[FLUX] Agent response: ${response}`);\n return response;\n } catch (error: any) {\n console.error(`[FLUX] Agent error: ${error.message}`);\n return \"Sorry, I encountered an error processing your message.\";\n }\n });\n\n // Connect and register\n await flux.connect();\n await flux.register();\n\n console.log(\"[FLUX] Agent running in production mode. Press Ctrl+C to stop.\");\n console.log(`[FLUX] Messages to ${phoneNumber} will be processed by your agent.\\n`);\n\n // Handle shutdown\n process.on(\"SIGINT\", async () => {\n console.log(\"\\n[FLUX] Shutting down...\");\n await flux.disconnect();\n process.exit(0);\n });\n\n // Keep alive\n await new Promise(() => {});\n}\n\nasync function main() {\n const command = process.argv[2];\n const flag = process.argv[3];\n\n switch (command) {\n case \"login\":\n await login();\n break;\n case \"logout\":\n logout();\n break;\n case \"run\":\n if (flag === \"--local\") {\n await runLocal();\n } else if (flag === \"--prod\" || !flag) {\n // Default to prod mode\n await runProd();\n } else {\n console.error(`[FLUX] Unknown flag: ${flag}`);\n console.log(\"Usage: flux run [--local | --prod]\");\n }\n break;\n case \"validate\":\n await validateCommand();\n break;\n case \"whoami\":\n const config = loadConfig();\n if (config.phoneNumber) {\n console.log(`[FLUX] Logged in as ${config.phoneNumber}`);\n } else {\n console.log(\"[FLUX] Not logged in.\");\n }\n break;\n default:\n console.log(\"Flux CLI - Connect LangChain agents to iMessage\\n\");\n console.log(\"Commands:\");\n console.log(\" flux login - Log in with your phone number\");\n console.log(\" flux logout - Log out\");\n console.log(\" flux validate - Check if agent.ts exports correctly\");\n console.log(\" flux run --local - Test agent locally (no server connection)\");\n console.log(\" flux run --prod - Run agent connected to bridge (default)\");\n console.log(\" flux whoami - Show current logged in user\");\n break;\n }\n}\n\nmain().catch(console.error);"]}
|
package/package.json
CHANGED
package/tsup.config.ts
CHANGED
|
@@ -2,13 +2,26 @@ import { defineConfig } from "tsup";
|
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
4
|
entry: ["src/cli.ts"],
|
|
5
|
-
format: ["cjs"],
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
format: ["cjs", "esm"],
|
|
6
|
+
dts: true,
|
|
7
|
+
sourcemap: true,
|
|
8
8
|
clean: true,
|
|
9
|
+
treeshake: true,
|
|
10
|
+
minify: false,
|
|
11
|
+
target: "es2022",
|
|
12
|
+
outDir: "dist",
|
|
13
|
+
platform: "node",
|
|
14
|
+
splitting: false,
|
|
15
|
+
bundle: true,
|
|
9
16
|
banner: {
|
|
10
17
|
js: "#!/usr/bin/env node",
|
|
11
18
|
},
|
|
12
|
-
|
|
13
|
-
|
|
19
|
+
external: [
|
|
20
|
+
"zod",
|
|
21
|
+
"nice-grpc",
|
|
22
|
+
"@grpc/grpc-js",
|
|
23
|
+
"nice-grpc-common",
|
|
24
|
+
"better-grpc",
|
|
25
|
+
"it-pushable",
|
|
26
|
+
],
|
|
14
27
|
});
|
package/.env
DELETED