mortgram-cli 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +41 -6
- package/dist/lib/config.js +8 -5
- package/dist/lib/logger.js +2 -1
- package/dist/lib/neural.js +26 -16
- package/dist/lib/spawner.js +5 -2
- package/dist/lib/vitals.js +2 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,6 +9,8 @@ const spawner_1 = require("./lib/spawner");
|
|
|
9
9
|
const config_1 = require("./lib/config");
|
|
10
10
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const axios_1 = __importDefault(require("axios"));
|
|
13
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
12
14
|
// Load environment variables from the parent directory if possible, or current
|
|
13
15
|
dotenv_1.default.config({ path: path_1.default.join(process.cwd(), "..", ".env.local"), quiet: true });
|
|
14
16
|
dotenv_1.default.config({ quiet: true }); // Fallback to current dir
|
|
@@ -16,20 +18,53 @@ const program = new commander_1.Command();
|
|
|
16
18
|
program
|
|
17
19
|
.name("mortgram")
|
|
18
20
|
.description("MORTGRAM Observer CLI - Zero-code observability wrapper")
|
|
19
|
-
.version("1.0.
|
|
21
|
+
.version("1.0.1");
|
|
20
22
|
program
|
|
21
23
|
.command("login <key>")
|
|
22
24
|
.description("Authenticate your terminal with your MORTGRAM API Key")
|
|
23
|
-
.action((key) => {
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
.action(async (key) => {
|
|
26
|
+
try {
|
|
27
|
+
const apiUrl = process.env.MORTGRAM_API_URL || "http://localhost:3000/api";
|
|
28
|
+
console.log(chalk_1.default.yellow("Authenticating with MORTGRAM HQ..."));
|
|
29
|
+
const res = await axios_1.default.get(`${apiUrl}/profile`, {
|
|
30
|
+
headers: { "Authorization": `Bearer ${key}` }
|
|
31
|
+
});
|
|
32
|
+
if (res.data.profile) {
|
|
33
|
+
const ablyKey = res.data.profile.ably_key;
|
|
34
|
+
(0, config_1.saveConfig)(key, ablyKey);
|
|
35
|
+
console.log(chalk_1.default.green("✔ Authentication successful."));
|
|
36
|
+
if (ablyKey) {
|
|
37
|
+
console.log(chalk_1.default.green("✔ Neural Link established (Ably Key retrieved)."));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
console.log(chalk_1.default.yellow("⚠ Neural Link warning: No Ably Key returned from server."));
|
|
41
|
+
}
|
|
42
|
+
console.log(chalk_1.default.gray("Configuration saved to ~/.mortgramrc"));
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.error(chalk_1.default.red("Authentication failed: Invalid response from server."));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error(chalk_1.default.red(`Authentication failed: ${error.message}`));
|
|
50
|
+
if (error.response?.status === 401) {
|
|
51
|
+
console.error(chalk_1.default.red("Error: Invalid API Key."));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
26
54
|
});
|
|
27
55
|
program
|
|
28
56
|
.command("run <command...>")
|
|
29
57
|
.description("Run an agent command with MORTGRAM observability")
|
|
30
58
|
.action(async (commandParts) => {
|
|
31
59
|
const fullCommand = commandParts.join(" ");
|
|
32
|
-
console.log(`MORTGRAM: Wrapping command: "${fullCommand}"`);
|
|
33
|
-
|
|
60
|
+
console.log(chalk_1.default.blue(`MORTGRAM: Wrapping command: "${fullCommand}"`));
|
|
61
|
+
console.log(chalk_1.default.blue(`MORTGRAM: Listening for uplink...`));
|
|
62
|
+
try {
|
|
63
|
+
await (0, spawner_1.spawnAgent)(fullCommand);
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
console.error(chalk_1.default.red(`MORTGRAM: Failed to launch agent: ${e.message}`));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
34
69
|
});
|
|
35
70
|
program.parse();
|
package/dist/lib/config.js
CHANGED
|
@@ -9,8 +9,8 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const os_1 = __importDefault(require("os"));
|
|
11
11
|
const CONFIG_FILE = path_1.default.join(os_1.default.homedir(), ".mortgramrc");
|
|
12
|
-
function saveConfig(
|
|
13
|
-
const config = { api_key:
|
|
12
|
+
function saveConfig(apiKey, ablyKey) {
|
|
13
|
+
const config = { api_key: apiKey, ably_key: ablyKey };
|
|
14
14
|
fs_1.default.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
15
15
|
}
|
|
16
16
|
function loadConfig() {
|
|
@@ -18,11 +18,14 @@ function loadConfig() {
|
|
|
18
18
|
try {
|
|
19
19
|
const content = fs_1.default.readFileSync(CONFIG_FILE, "utf-8");
|
|
20
20
|
const config = JSON.parse(content);
|
|
21
|
-
return
|
|
21
|
+
return {
|
|
22
|
+
api_key: config.api_key || null,
|
|
23
|
+
ably_key: config.ably_key || null
|
|
24
|
+
};
|
|
22
25
|
}
|
|
23
26
|
catch (e) {
|
|
24
|
-
return null;
|
|
27
|
+
return { api_key: null, ably_key: null };
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
|
-
return null;
|
|
30
|
+
return { api_key: null, ably_key: null };
|
|
28
31
|
}
|
package/dist/lib/logger.js
CHANGED
|
@@ -9,7 +9,8 @@ const dotenv_1 = __importDefault(require("dotenv"));
|
|
|
9
9
|
const config_1 = require("./config");
|
|
10
10
|
// ensure env is loaded
|
|
11
11
|
dotenv_1.default.config({ quiet: true });
|
|
12
|
-
const
|
|
12
|
+
const config = (0, config_1.loadConfig)();
|
|
13
|
+
const API_KEY = process.env.MG_LIVE_KEY || config.api_key;
|
|
13
14
|
const API_URL = process.env.MORTGRAM_API_URL || "http://localhost:3000/api/ingest";
|
|
14
15
|
const AGENT_ID = process.env.MG_AGENT_ID || "cli-agent";
|
|
15
16
|
async function ingestLog(type, content, metadata = {}) {
|
package/dist/lib/neural.js
CHANGED
|
@@ -5,29 +5,39 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.startNeuralLink = startNeuralLink;
|
|
7
7
|
const ably_1 = __importDefault(require("ably"));
|
|
8
|
+
const logger_1 = require("./logger");
|
|
8
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
10
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const AGENT_ID = process.env.MG_AGENT_ID || "cli-agent";
|
|
13
|
-
let client = null;
|
|
11
|
+
const config_1 = require("./config");
|
|
12
|
+
dotenv_1.default.config({ quiet: true });
|
|
14
13
|
async function startNeuralLink(childProcess) {
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const config = (0, config_1.loadConfig)();
|
|
15
|
+
const API_KEY = process.env.ABLY_API_KEY || config.ably_key;
|
|
16
|
+
const AGENT_ID = process.env.MG_AGENT_ID || "cli-agent"; // In real usage, this might be dynamic or passed as arg
|
|
17
|
+
if (!API_KEY) {
|
|
18
|
+
console.log(chalk_1.default.yellow("MORTGRAM: No ABLY_API_KEY found. Neural link disabled."));
|
|
17
19
|
return { close: () => { } };
|
|
18
20
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const realtime = new ably_1.default.Realtime(API_KEY);
|
|
22
|
+
// Connect to specific agent control channel
|
|
23
|
+
const channel = realtime.channels.get(`control:${AGENT_ID}`);
|
|
24
|
+
await channel.subscribe("kill", async (message) => {
|
|
25
|
+
console.log(chalk_1.default.red.bold("\n⚡ MORTGRAM: KILL SIGNAL RECEIVED ⚡"));
|
|
26
|
+
console.log(chalk_1.default.red(`Reason: ${message.data.reason || "Manual Termination"}`));
|
|
27
|
+
// Log the event before dying
|
|
28
|
+
await (0, logger_1.ingestLog)("action", "TERMINATED via Neural Link", {
|
|
29
|
+
status: "killed",
|
|
30
|
+
reason: message.data.reason
|
|
31
|
+
});
|
|
32
|
+
// Kill the child process
|
|
33
|
+
childProcess.kill("SIGKILL");
|
|
34
|
+
// Close Ably connection
|
|
35
|
+
realtime.close();
|
|
24
36
|
process.exit(0);
|
|
25
37
|
});
|
|
26
|
-
|
|
38
|
+
// Also subscribe to PAUSE signals if we implement them later
|
|
39
|
+
// await channel.subscribe("pause", ...);
|
|
27
40
|
return {
|
|
28
|
-
close: () =>
|
|
29
|
-
if (client)
|
|
30
|
-
client.close();
|
|
31
|
-
}
|
|
41
|
+
close: () => realtime.close()
|
|
32
42
|
};
|
|
33
43
|
}
|
package/dist/lib/spawner.js
CHANGED
|
@@ -13,8 +13,9 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
13
13
|
let childProcess = null;
|
|
14
14
|
async function spawnAgent(command) {
|
|
15
15
|
console.log(chalk_1.default.green("MORTGRAM: Initializing Observer..."));
|
|
16
|
+
// Immediate handshake
|
|
17
|
+
await (0, logger_1.ingestLog)("log", "Observer Linked. Awaiting agent output.", { status: "online" });
|
|
16
18
|
// Parse command string into cmd and args
|
|
17
|
-
// crude parsing, careful with quotes
|
|
18
19
|
const parts = command.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
|
|
19
20
|
if (parts.length === 0)
|
|
20
21
|
return;
|
|
@@ -44,8 +45,10 @@ async function spawnAgent(command) {
|
|
|
44
45
|
process.stderr.write(line); // Pass through
|
|
45
46
|
analyzeLog(line, true);
|
|
46
47
|
});
|
|
47
|
-
childProcess.on('close', (code) => {
|
|
48
|
+
childProcess.on('close', async (code) => {
|
|
48
49
|
console.log(chalk_1.default.gray(`MORTGRAM: Child process exited with code ${code}`));
|
|
50
|
+
// Final log
|
|
51
|
+
await (0, logger_1.ingestLog)("log", `Agent process terminated (code ${code})`, { status: "offline" });
|
|
49
52
|
clearInterval(vitalsInterval);
|
|
50
53
|
neural.close();
|
|
51
54
|
process.exit(code);
|
package/dist/lib/vitals.js
CHANGED
|
@@ -10,7 +10,8 @@ const guard_1 = require("./guard");
|
|
|
10
10
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
11
11
|
const config_1 = require("./config");
|
|
12
12
|
dotenv_1.default.config({ quiet: true });
|
|
13
|
-
const
|
|
13
|
+
const config = (0, config_1.loadConfig)();
|
|
14
|
+
const API_KEY = process.env.MG_LIVE_KEY || config.api_key;
|
|
14
15
|
const API_URL = process.env.MORTGRAM_API_URL ? `${process.env.MORTGRAM_API_URL}/heartbeat` : "http://localhost:3000/api/cron/heartbeat";
|
|
15
16
|
// Note: reusing cron heartbeat or creating a specific agent heartbeat endpoint?
|
|
16
17
|
// For CLI, we likely want a direct ingestion endpoint or use the log ingestion with type "heartbeat"
|