@fml-inc/fml 0.6.1 → 0.7.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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +15 -2
- package/dist/{chunk-2H6D7RUN.js → chunk-PTUZMKSN.js} +6 -4
- package/dist/chunk-PTUZMKSN.js.map +1 -0
- package/dist/chunk-S4TJNLEN.js +61 -0
- package/dist/chunk-S4TJNLEN.js.map +1 -0
- package/dist/{chunk-VDW5L7OB.js → chunk-VV4JHH4H.js} +38 -6
- package/dist/chunk-VV4JHH4H.js.map +1 -0
- package/dist/cli.js +168 -53
- package/dist/cli.js.map +1 -1
- package/dist/daemon-MSLDHLMH.js +21 -0
- package/dist/mcp/server.js +5 -5
- package/dist/mcp/server.js.map +1 -1
- package/dist/{token-store-JZJ3FJHA.js → token-store-3IQSLOTQ.js} +6 -2
- package/package.json +1 -1
- package/dist/chunk-2H6D7RUN.js.map +0 -1
- package/dist/chunk-VDW5L7OB.js.map +0 -1
- package/dist/chunk-ZFUJ5ZQP.js +0 -41
- package/dist/chunk-ZFUJ5ZQP.js.map +0 -1
- package/dist/daemon-J27JBWLV.js +0 -17
- /package/dist/{daemon-J27JBWLV.js.map → daemon-MSLDHLMH.js.map} +0 -0
- /package/dist/{token-store-JZJ3FJHA.js.map → token-store-3IQSLOTQ.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createFmlClient,
|
|
4
4
|
getAuthenticatedClient
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-PTUZMKSN.js";
|
|
6
6
|
import {
|
|
7
7
|
CONVEX_URL,
|
|
8
8
|
DEFAULT_SYNC_URL,
|
|
9
9
|
DEFAULT_TARGET_NAME,
|
|
10
10
|
FML_DATA_DIR,
|
|
11
11
|
FML_LOG_DIR,
|
|
12
|
+
SERVICE_TOKEN_LOGIN_USER_ID,
|
|
12
13
|
Sentry,
|
|
13
14
|
WORKOS_API_URL,
|
|
14
15
|
WORKOS_AUTH_URL,
|
|
@@ -22,16 +23,19 @@ import {
|
|
|
22
23
|
isValidEnvName,
|
|
23
24
|
readTokens,
|
|
24
25
|
setSelectedOrg,
|
|
26
|
+
storeServiceRefreshToken,
|
|
25
27
|
writeEnvConfig,
|
|
26
28
|
writeTokens
|
|
27
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-VV4JHH4H.js";
|
|
28
30
|
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
handleFmlStart,
|
|
32
|
+
handleFmlStop,
|
|
33
|
+
handlePanopticonStart,
|
|
34
|
+
handlePanopticonStop,
|
|
31
35
|
handleSyncStart,
|
|
32
36
|
handleSyncStop,
|
|
33
37
|
parsePanopticonRunning
|
|
34
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-S4TJNLEN.js";
|
|
35
39
|
import {
|
|
36
40
|
execBinSync,
|
|
37
41
|
panopticonExec,
|
|
@@ -88,7 +92,7 @@ async function handleDoctor(opts) {
|
|
|
88
92
|
token = await getValidToken();
|
|
89
93
|
if (token) {
|
|
90
94
|
const stored = readTokens();
|
|
91
|
-
const detail = stored?.user?.email ? `Logged in as ${stored.user.email}` : "Token present";
|
|
95
|
+
const detail = stored?.tokenType === "service" && stored.user.id === SERVICE_TOKEN_LOGIN_USER_ID ? "Service token configured" : stored?.user?.email ? `Logged in as ${stored.user.email}` : "Token present";
|
|
92
96
|
pushAndReport({ label: "Auth", status: "ok", detail }, spinner);
|
|
93
97
|
} else {
|
|
94
98
|
pushAndReport(
|
|
@@ -705,7 +709,7 @@ function handleUninstall(opts) {
|
|
|
705
709
|
// src/commands/update.ts
|
|
706
710
|
import { execSync as execSync2 } from "child_process";
|
|
707
711
|
async function handleUpdate() {
|
|
708
|
-
const currentVersion = true ? "0.
|
|
712
|
+
const currentVersion = true ? "0.7.0+8fe6800" : "unknown";
|
|
709
713
|
console.log(`Current: ${currentVersion}`);
|
|
710
714
|
console.log("Updating via npm...\n");
|
|
711
715
|
try {
|
|
@@ -1022,7 +1026,60 @@ async function linkGitHubIdentity() {
|
|
|
1022
1026
|
console.warn(`[fml] Failed to link GitHub identity: ${msg}`);
|
|
1023
1027
|
}
|
|
1024
1028
|
}
|
|
1025
|
-
function
|
|
1029
|
+
function promptHidden(question) {
|
|
1030
|
+
if (!process.stdin.isTTY) {
|
|
1031
|
+
return new Promise((resolve, reject) => {
|
|
1032
|
+
let input = "";
|
|
1033
|
+
process.stdin.setEncoding("utf8");
|
|
1034
|
+
process.stdin.on("data", (chunk) => {
|
|
1035
|
+
input += chunk;
|
|
1036
|
+
});
|
|
1037
|
+
process.stdin.once("end", () => resolve(input.trim()));
|
|
1038
|
+
process.stdin.once("error", reject);
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
return new Promise((resolve, reject) => {
|
|
1042
|
+
const stdin = process.stdin;
|
|
1043
|
+
const wasRaw = stdin.isRaw === true;
|
|
1044
|
+
let value = "";
|
|
1045
|
+
let settled = false;
|
|
1046
|
+
const cleanup = () => {
|
|
1047
|
+
stdin.off("data", onData);
|
|
1048
|
+
stdin.setRawMode(wasRaw);
|
|
1049
|
+
stdin.pause();
|
|
1050
|
+
process.stderr.write("\n");
|
|
1051
|
+
};
|
|
1052
|
+
const finish = (fn) => {
|
|
1053
|
+
if (settled) return;
|
|
1054
|
+
settled = true;
|
|
1055
|
+
cleanup();
|
|
1056
|
+
fn();
|
|
1057
|
+
};
|
|
1058
|
+
const onData = (chunk) => {
|
|
1059
|
+
const text = chunk.toString("utf8");
|
|
1060
|
+
for (const char of text) {
|
|
1061
|
+
if (char === "") {
|
|
1062
|
+
finish(() => reject(new Error("Canceled")));
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
if (char === "\r" || char === "\n") {
|
|
1066
|
+
finish(() => resolve(value.trim()));
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
if (char === "\x7F" || char === "\b") {
|
|
1070
|
+
value = value.slice(0, -1);
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
value += char;
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
process.stderr.write(question);
|
|
1077
|
+
stdin.setRawMode(true);
|
|
1078
|
+
stdin.resume();
|
|
1079
|
+
stdin.on("data", onData);
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
function upgradeSyncTargetAfterLogin(opts) {
|
|
1026
1083
|
try {
|
|
1027
1084
|
const { name: envName } = getActiveEnv();
|
|
1028
1085
|
if (!isValidEnvName(envName)) {
|
|
@@ -1044,11 +1101,12 @@ function upgradeSyncTargetAfterLogin() {
|
|
|
1044
1101
|
console.log("Restart panopticon to apply: fml stop && fml start");
|
|
1045
1102
|
return;
|
|
1046
1103
|
}
|
|
1047
|
-
if (existing.token) return;
|
|
1104
|
+
if (existing.token && !opts?.forceTokenCommand) return;
|
|
1048
1105
|
if (existing.tokenCommand === pinnedCmd) return;
|
|
1049
|
-
if (existing.tokenCommand && existing.tokenCommand !== "fml sync-token") {
|
|
1106
|
+
if (!opts?.forceTokenCommand && existing.tokenCommand && existing.tokenCommand !== "fml sync-token") {
|
|
1050
1107
|
return;
|
|
1051
1108
|
}
|
|
1109
|
+
delete existing.token;
|
|
1052
1110
|
existing.tokenCommand = pinnedCmd;
|
|
1053
1111
|
saveSyncConfig(config2);
|
|
1054
1112
|
console.log(`Sync target "${envName}" now using ${pinnedCmd}.`);
|
|
@@ -1058,32 +1116,75 @@ function upgradeSyncTargetAfterLogin() {
|
|
|
1058
1116
|
console.warn(`[fml] Could not update sync target: ${msg}`);
|
|
1059
1117
|
}
|
|
1060
1118
|
}
|
|
1061
|
-
async function selectOrg() {
|
|
1119
|
+
async function selectOrg(envName) {
|
|
1062
1120
|
try {
|
|
1063
|
-
const token = await getValidToken();
|
|
1121
|
+
const token = await getValidToken({ env: envName });
|
|
1064
1122
|
if (!token) return;
|
|
1065
1123
|
const api = createFmlClient(token);
|
|
1066
1124
|
const orgs = await api.queryOrgs();
|
|
1067
1125
|
if (orgs.length === 0) return;
|
|
1068
|
-
const current = getSelectedOrg();
|
|
1126
|
+
const current = getSelectedOrg(envName);
|
|
1069
1127
|
const org = current && orgs.find((o) => (o.slug ?? o.name) === current) || orgs[0];
|
|
1070
1128
|
const slug = org.slug ?? org.name;
|
|
1071
|
-
setSelectedOrg(slug);
|
|
1129
|
+
setSelectedOrg(slug, envName);
|
|
1072
1130
|
console.log(`Selected org: ${org.name} (${slug})`);
|
|
1073
1131
|
} catch {
|
|
1074
1132
|
}
|
|
1075
1133
|
}
|
|
1134
|
+
async function runServiceTokenLogin(refreshToken) {
|
|
1135
|
+
const { name: envName } = getActiveEnv();
|
|
1136
|
+
if (!isValidEnvName(envName)) {
|
|
1137
|
+
throw new Error(
|
|
1138
|
+
`Cannot store service-token login for unsafe env name "${envName}".`
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
console.log(`Signing in to FML with a service token (${envName})...`);
|
|
1142
|
+
const token = refreshToken ?? await promptHidden("Paste FML service refresh token (fml_srt_*): ");
|
|
1143
|
+
const ok = await storeServiceRefreshToken(token, { env: envName });
|
|
1144
|
+
if (!ok) {
|
|
1145
|
+
throw new Error("Service token login failed.");
|
|
1146
|
+
}
|
|
1147
|
+
await selectOrg(envName);
|
|
1148
|
+
upgradeSyncTargetAfterLogin({ forceTokenCommand: true });
|
|
1149
|
+
console.log("Logged in with FML service token.");
|
|
1150
|
+
console.log("Queries and sync will use the stored service token.");
|
|
1151
|
+
console.log("You're all set! Restart Claude Code to use FML tools.");
|
|
1152
|
+
}
|
|
1153
|
+
async function handleServiceTokenLogin(refreshToken) {
|
|
1154
|
+
try {
|
|
1155
|
+
await runServiceTokenLogin(refreshToken);
|
|
1156
|
+
process.exit(0);
|
|
1157
|
+
} catch (err) {
|
|
1158
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1159
|
+
if (msg === "Canceled") {
|
|
1160
|
+
console.error("Login canceled.");
|
|
1161
|
+
process.exit(1);
|
|
1162
|
+
}
|
|
1163
|
+
Sentry.captureException(err);
|
|
1164
|
+
console.error(`Login failed: ${msg}`);
|
|
1165
|
+
process.exit(1);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1076
1168
|
async function handleLogin(opts) {
|
|
1169
|
+
if (opts?.serviceToken) {
|
|
1170
|
+
await handleServiceTokenLogin();
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1077
1173
|
const { name: envName } = getActiveEnv();
|
|
1078
1174
|
const existingToken = await getValidToken();
|
|
1079
1175
|
if (existingToken) {
|
|
1080
|
-
const { readTokens: readTokens2 } = await import("./token-store-
|
|
1176
|
+
const { readTokens: readTokens2 } = await import("./token-store-3IQSLOTQ.js");
|
|
1081
1177
|
const stored = readTokens2();
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1178
|
+
if (stored?.tokenType === "service") {
|
|
1179
|
+
const label = stored.user.id === SERVICE_TOKEN_LOGIN_USER_ID ? "a service token" : `${stored.user.name} (${stored.user.email})`;
|
|
1180
|
+
console.log(`Already logged in with ${label} on ${envName}.`);
|
|
1181
|
+
} else {
|
|
1182
|
+
console.log(
|
|
1183
|
+
`Already logged in as ${stored?.user.name} (${stored?.user.email}) on ${envName}.`
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1085
1186
|
await linkGitHubIdentity();
|
|
1086
|
-
await selectOrg();
|
|
1187
|
+
await selectOrg(envName);
|
|
1087
1188
|
upgradeSyncTargetAfterLogin();
|
|
1088
1189
|
console.log("You're all set! Restart Claude Code to use FML tools.");
|
|
1089
1190
|
process.exit(0);
|
|
@@ -1100,7 +1201,7 @@ async function handleLogin(opts) {
|
|
|
1100
1201
|
console.log(`
|
|
1101
1202
|
Logged in as ${result.name} (${result.email})`);
|
|
1102
1203
|
await linkGitHubIdentity();
|
|
1103
|
-
await selectOrg();
|
|
1204
|
+
await selectOrg(envName);
|
|
1104
1205
|
upgradeSyncTargetAfterLogin();
|
|
1105
1206
|
console.log("You're all set! Restart Claude Code to use FML tools.");
|
|
1106
1207
|
process.exit(0);
|
|
@@ -1204,7 +1305,11 @@ async function handleStatus() {
|
|
|
1204
1305
|
}
|
|
1205
1306
|
const tokenValid = await getValidToken();
|
|
1206
1307
|
console.log("Authentication:");
|
|
1207
|
-
|
|
1308
|
+
if (tokens.tokenType === "service" && tokens.user.id === SERVICE_TOKEN_LOGIN_USER_ID) {
|
|
1309
|
+
console.log(" Auth: service token");
|
|
1310
|
+
} else {
|
|
1311
|
+
console.log(` User: ${tokens.user.name} (${tokens.user.email})`);
|
|
1312
|
+
}
|
|
1208
1313
|
console.log(
|
|
1209
1314
|
` Token: ${tokenValid ? "valid" : "expired (needs refresh/re-login)"}`
|
|
1210
1315
|
);
|
|
@@ -1386,9 +1491,9 @@ async function handleEnvSwitch(target) {
|
|
|
1386
1491
|
writeEnvConfig({ active: target });
|
|
1387
1492
|
const convexUrl = match.url.replace(".convex.site", ".convex.cloud");
|
|
1388
1493
|
console.log(`Switched to ${target}: ${convexUrl}`);
|
|
1389
|
-
console.log("\nRestarting
|
|
1390
|
-
|
|
1391
|
-
await
|
|
1494
|
+
console.log("\nRestarting local collection...");
|
|
1495
|
+
handlePanopticonStop();
|
|
1496
|
+
await handlePanopticonStart();
|
|
1392
1497
|
console.log(
|
|
1393
1498
|
"MCP server will pick up the change on next Claude Code session."
|
|
1394
1499
|
);
|
|
@@ -1961,7 +2066,7 @@ async function handleConfigDetail(opts) {
|
|
|
1961
2066
|
// src/commands/tools.ts
|
|
1962
2067
|
import { readFileSync } from "fs";
|
|
1963
2068
|
import path3 from "path";
|
|
1964
|
-
var pluginVersion = true ? "0.
|
|
2069
|
+
var pluginVersion = true ? "0.7.0+8fe6800" : void 0;
|
|
1965
2070
|
async function getApi() {
|
|
1966
2071
|
const api = await getAuthenticatedClient();
|
|
1967
2072
|
if (!api) {
|
|
@@ -2017,6 +2122,12 @@ async function handleToolsList(opts) {
|
|
|
2017
2122
|
console.log("No tools found.");
|
|
2018
2123
|
return;
|
|
2019
2124
|
}
|
|
2125
|
+
console.log("Backend tools available to this FML session.\n");
|
|
2126
|
+
console.log("Next steps:");
|
|
2127
|
+
console.log(" fml tools describe <tool> --json Inspect args/schema");
|
|
2128
|
+
console.log(" fml tools call <tool> --args '{...}' Run a tool");
|
|
2129
|
+
console.log(" fml tools list --json Machine-readable catalog");
|
|
2130
|
+
console.log("");
|
|
2020
2131
|
const nameW = Math.min(
|
|
2021
2132
|
40,
|
|
2022
2133
|
Math.max(...descriptors.map((d) => d.name.length), 4)
|
|
@@ -2091,56 +2202,60 @@ await initSentry();
|
|
|
2091
2202
|
if (process.argv.length <= 2 || process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
2092
2203
|
printBanner();
|
|
2093
2204
|
}
|
|
2094
|
-
var program = new Command().name("fml").description("FML agent tools
|
|
2095
|
-
true ? "0.
|
|
2205
|
+
var program = new Command().name("fml").description("FML CLI and agent tools").version(
|
|
2206
|
+
true ? "0.7.0+8fe6800" : "dev"
|
|
2096
2207
|
);
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
).map((o) => o.mandatory ? o.flags : `[${o.flags}]`).join(" ");
|
|
2104
|
-
const usage = [name, args, opts].filter(Boolean).join(" ");
|
|
2105
|
-
return `${usage}
|
|
2208
|
+
function formatCommandInventory(cmd, prefix = "") {
|
|
2209
|
+
const name = prefix ? `${prefix} ${cmd.name()}` : cmd.name();
|
|
2210
|
+
const args = cmd.registeredArguments.map((a) => a.required ? `<${a.name()}>` : `[${a.name()}]`).join(" ");
|
|
2211
|
+
const opts = cmd.options.filter((o) => !o.hidden && o.long !== "--help" && o.long !== "--version").map((o) => o.mandatory ? o.flags : `[${o.flags}]`).join(" ");
|
|
2212
|
+
const usage = [name, args, opts].filter(Boolean).join(" ");
|
|
2213
|
+
return `${usage}
|
|
2106
2214
|
${cmd.description()}`;
|
|
2107
|
-
|
|
2108
|
-
|
|
2215
|
+
}
|
|
2216
|
+
var tools = program.command("tools").description("List backend tools available via the dynamic catalog").option("--category <category>", "Filter by category").option("--json", "Output as JSON").action((opts) => handleToolsList(opts));
|
|
2217
|
+
program.command("commands", { hidden: true }).description("List CLI commands, including hidden/internal commands").action(() => {
|
|
2218
|
+
const lines = program.commands.filter((c) => c.name() !== "commands" && c.name() !== "help").flatMap((c) => {
|
|
2109
2219
|
if (c.commands.length > 0) {
|
|
2110
|
-
return c.commands.map((s) =>
|
|
2220
|
+
return c.commands.map((s) => formatCommandInventory(s, c.name()));
|
|
2111
2221
|
}
|
|
2112
|
-
return [
|
|
2222
|
+
return [formatCommandInventory(c)];
|
|
2113
2223
|
});
|
|
2114
2224
|
console.log(lines.join("\n\n"));
|
|
2115
2225
|
});
|
|
2116
2226
|
tools.command("list").description("List backend tools available via the dynamic catalog").option("--category <category>", "Filter by category").option("--json", "Output as JSON").action((opts) => handleToolsList(opts));
|
|
2117
2227
|
tools.command("describe").description("Show description and input schema for a backend tool").argument("<name>", "Tool name (e.g. integration-github)").option("--json", "Output as JSON").action((name, opts) => handleToolsDescribe(name, opts));
|
|
2118
2228
|
tools.command("call").description("Invoke a backend tool by name with JSON args").argument("<name>", "Tool name").option("--args <json>", "Args as a JSON string (defaults to {})").option("--file <path>", "Path to a JSON file containing args").action((name, opts) => handleToolsCall(name, opts));
|
|
2119
|
-
program.command("install").description("
|
|
2229
|
+
program.command("install").description("Set up FML for local agent use").option(
|
|
2120
2230
|
"--force",
|
|
2121
2231
|
"Reinstall even if already set up (upgrades panopticon, re-registers plugin)"
|
|
2122
2232
|
).action((opts) => handleInstall(opts));
|
|
2123
|
-
program.command("uninstall").description("Remove
|
|
2233
|
+
program.command("uninstall").description("Remove FML agent integrations and optionally local data").option(
|
|
2124
2234
|
"--target <target>",
|
|
2125
2235
|
"Target CLI: claude, gemini, codex, claude-desktop, all"
|
|
2126
2236
|
).option("--purge", "Also remove all data, logs, and auth tokens").action((opts) => handleUninstall(opts));
|
|
2127
2237
|
program.command("update").description("Update fml to the latest version").action(() => handleUpdate());
|
|
2128
|
-
program.command("login").description("Sign in to your FML account").option("--device", "Use device authorization flow (no browser needed)").
|
|
2238
|
+
program.command("login").description("Sign in to your FML account").option("--device", "Use device authorization flow (no browser needed)").option(
|
|
2239
|
+
"--service-token",
|
|
2240
|
+
"Sign in with an org service refresh token (prompts for fml_srt_*)"
|
|
2241
|
+
).action(
|
|
2242
|
+
(opts) => handleLogin(opts)
|
|
2243
|
+
);
|
|
2129
2244
|
program.command("logout").description("Sign out and clear stored credentials").action(() => handleLogout());
|
|
2130
2245
|
program.command("org").description("Show or select organization").argument("[slug]", "Org slug to select").action((slug) => handleOrg(slug));
|
|
2131
|
-
program.command("status").description("Show
|
|
2246
|
+
program.command("status").description("Show auth and local service status").action(() => handleStatus());
|
|
2132
2247
|
program.command("doctor").description("Check FML and panopticon configuration and connectivity").option("--json", "Output as JSON").action((opts) => handleDoctor(opts));
|
|
2133
2248
|
program.command("open").description("Open FML dashboard in browser").option("--json", "Output URL as JSON instead of opening browser").action((opts) => handleOpen(opts));
|
|
2134
|
-
program.command("env").description("Show or switch environment
|
|
2249
|
+
program.command("env").description("Show or switch FML backend environment").argument("[target]", "Environment name or backend URL").action((target) => {
|
|
2135
2250
|
if (target) handleEnvSwitch(target);
|
|
2136
2251
|
else handleEnvShow();
|
|
2137
2252
|
});
|
|
2138
|
-
program.command("start").description("Start
|
|
2139
|
-
program.command("stop").description("Stop
|
|
2140
|
-
var panopticon = program.command("panopticon").description("Start or stop the panopticon server");
|
|
2141
|
-
panopticon.command("start").description("Start the panopticon server").action(() =>
|
|
2142
|
-
panopticon.command("stop").description("Stop the panopticon server").action(() =>
|
|
2143
|
-
var sync = program.command("sync").description("Manage sync configuration");
|
|
2253
|
+
program.command("start").description("Start FML local collection and sync").action(() => handleFmlStart());
|
|
2254
|
+
program.command("stop").description("Stop FML local collection and sync").action(() => handleFmlStop());
|
|
2255
|
+
var panopticon = program.command("panopticon", { hidden: true }).description("Start or stop the panopticon server");
|
|
2256
|
+
panopticon.command("start").description("Start the panopticon server").action(() => handlePanopticonStart());
|
|
2257
|
+
panopticon.command("stop").description("Stop the panopticon server").action(() => handlePanopticonStop());
|
|
2258
|
+
var sync = program.command("sync").description("Manage sync configuration and troubleshooting");
|
|
2144
2259
|
sync.command("start").description("Start syncing to configured targets (enable sync)").action(() => handleSyncStart());
|
|
2145
2260
|
sync.command("stop").description("Stop syncing (disable sync; leaves targets configured)").action(() => handleSyncStop());
|
|
2146
2261
|
sync.command("setup").description("Configure sync targets (convenience shortcut)").action(() => handleSyncSetup());
|
|
@@ -2162,9 +2277,9 @@ program.command("sync-token", { hidden: true }).description(
|
|
|
2162
2277
|
).action((opts) => handleSyncToken(opts));
|
|
2163
2278
|
program.command("activity").description("Activity summary \u2014 sessions, prompts, tools, costs").option("--since <duration>", 'Time window, e.g. "24h", "7d"').action((opts) => handleActivity(opts));
|
|
2164
2279
|
program.command("sessions").description("List recent sessions").option("--since <duration>", 'Time filter, e.g. "24h", "7d"').option("--limit <n>", "Max sessions to return").action((opts) => handleSessions(opts));
|
|
2165
|
-
program.command("timeline").description("Get events for a session").argument("<session-id>", "Session ID").option("--limit <n>", "Max events to return").option("--offset <n>", "Events to skip").action((sessionId, opts) => handleTimeline(sessionId, opts));
|
|
2280
|
+
program.command("timeline").description("Get events for a session from `fml sessions`").argument("<session-id>", "Session ID from `fml sessions`").option("--limit <n>", "Max events to return").option("--offset <n>", "Events to skip").action((sessionId, opts) => handleTimeline(sessionId, opts));
|
|
2166
2281
|
program.command("spending").description("AI token usage and cost breakdown").option("--since <duration>", 'Time filter, e.g. "24h", "7d"').option("--group-by <key>", "Group by: session, model, or day").action((opts) => handleSpending(opts));
|
|
2167
|
-
program.command("search").description("Search
|
|
2282
|
+
program.command("search").description("Search FML agent sessions").argument("<query>", "Text to search for").option("--since <duration>", 'Time filter, e.g. "24h", "7d"').option("--limit <n>", "Max results").action((query, opts) => handleSearch(query, opts));
|
|
2168
2283
|
program.command("query", { hidden: true }).description("Query a connected integration").argument(
|
|
2169
2284
|
"<provider>",
|
|
2170
2285
|
"Provider name (sentry, slack, github, linear, notion, freshdesk, stripe, posthog, amplitude, meta-ads)"
|