@fml-inc/fml 0.8.6-rc.2 → 0.8.6
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 -10
- package/dist/{chunk-FGR7SHV7.js → chunk-2DQQXBWM.js} +1 -1
- package/dist/{chunk-3T5UCGBR.js → chunk-5TOOBX7I.js} +1 -1
- package/dist/{chunk-KWCFT54L.js → chunk-B3H2YWPJ.js} +39 -17
- package/dist/{chunk-GQ2WVOGY.js → chunk-E2MATWOU.js} +3 -3
- package/dist/{chunk-RZ5LWWRO.js → chunk-LOJPIJZW.js} +2 -2
- package/dist/{chunk-GST2GTOC.js → chunk-PJWMSHHZ.js} +1 -1
- package/dist/{chunk-Z2LWDZ6Z.js → chunk-V2XC7JTB.js} +1 -1
- package/dist/{chunk-JEZPS7F5.js → chunk-YFHZJPTC.js} +1 -1
- package/dist/cli.js +170 -50
- package/dist/hook-handler.js +4 -4
- package/dist/mcp/server.js +2 -2
- package/dist/observer-server.js +7 -7
- package/dist/pi/extension.js +20 -15
- package/dist/sync-cycle.js +3 -3
- package/dist/{token-store-TEPDSK2A.js → token-store-ORR5MIJL.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,19 +25,24 @@ npm install --global @fml-inc/fml
|
|
|
25
25
|
fml setup
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
For a customer-hosted deployment, pass
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
For a customer-hosted deployment, pass the address you use to open FML in the
|
|
29
|
+
browser to setup instead. The CLI asks that app for its backend (Convex HTTP
|
|
30
|
+
actions) origin, signs in against it, and only then saves both as the active
|
|
31
|
+
`custom` environment and restarts the observer, so later CLI and observer
|
|
32
|
+
traffic uses the same deployment and a failed login never switches
|
|
33
|
+
environments:
|
|
32
34
|
|
|
33
35
|
```bash
|
|
34
|
-
fml
|
|
35
|
-
#
|
|
36
|
-
fml login https://
|
|
36
|
+
fml setup https://fml.example.com
|
|
37
|
+
# Sign in again later, or headless:
|
|
38
|
+
fml login https://fml.example.com
|
|
39
|
+
fml login https://fml.example.com --device
|
|
37
40
|
```
|
|
38
41
|
|
|
39
|
-
The
|
|
40
|
-
|
|
42
|
+
The backend origin itself (for example `https://actions.fml.example.com`) is
|
|
43
|
+
also accepted. Either URL must be an HTTPS origin with no path, query,
|
|
44
|
+
credentials, or fragment. Plain HTTP is accepted only for loopback development
|
|
45
|
+
servers.
|
|
41
46
|
|
|
42
47
|
Run `fml update` to check for and install a newer global package with npm. It
|
|
43
48
|
reports the version installed and refreshes FML setup automatically. Stable
|
|
@@ -308,7 +313,7 @@ fml tools call <tool-name> --args '{"key":"value"}'
|
|
|
308
313
|
## CLI overview
|
|
309
314
|
|
|
310
315
|
```text
|
|
311
|
-
fml setup
|
|
316
|
+
fml setup [backend-url] Install integrations, sign in if needed, and start FML
|
|
312
317
|
fml install Register FML agent integrations and the MCP server
|
|
313
318
|
fml uninstall Remove agent integration; add --purge to remove local state
|
|
314
319
|
fml update Update @fml-inc/fml with npm (stable: latest; prerelease: next)
|
|
@@ -192,12 +192,20 @@ function ensureDirs() {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
// src/config.ts
|
|
195
|
-
var DEFAULT_PROD_URL = "https://
|
|
196
|
-
var DEFAULT_SYNC_URL = DEFAULT_PROD_URL.replace(
|
|
197
|
-
".convex.cloud",
|
|
198
|
-
".convex.site"
|
|
199
|
-
);
|
|
195
|
+
var DEFAULT_PROD_URL = "https://api.fml.inc";
|
|
200
196
|
var DEFAULT_TARGET_NAME = "fml";
|
|
197
|
+
var LEGACY_HOSTED_BACKEND_URLS = [
|
|
198
|
+
"https://trustworthy-chihuahua-382.convex.site"
|
|
199
|
+
];
|
|
200
|
+
function isHostedBackendUrl(url) {
|
|
201
|
+
let normalized;
|
|
202
|
+
try {
|
|
203
|
+
normalized = normalizeConvexUrl(url);
|
|
204
|
+
} catch {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
return normalized === DEFAULT_PROD_URL || LEGACY_HOSTED_BACKEND_URLS.includes(normalized);
|
|
208
|
+
}
|
|
201
209
|
var ENV_CONFIG_PATH = path2.join(FML_DATA_DIR, "env.json");
|
|
202
210
|
var ENV_NAME_RE = /^[A-Za-z0-9_-]+$/;
|
|
203
211
|
function isValidEnvName(envName) {
|
|
@@ -211,7 +219,10 @@ function normalizeConvexUrl(value) {
|
|
|
211
219
|
"FML environment URL must be HTTPS (HTTP is allowed only for loopback) with no path, credentials, query, or fragment"
|
|
212
220
|
);
|
|
213
221
|
}
|
|
214
|
-
return
|
|
222
|
+
return url.origin;
|
|
223
|
+
}
|
|
224
|
+
function normalizeAppUrl(value) {
|
|
225
|
+
return normalizeConvexUrl(value);
|
|
215
226
|
}
|
|
216
227
|
function readEnvConfig() {
|
|
217
228
|
try {
|
|
@@ -233,14 +244,19 @@ function readEnvConfig() {
|
|
|
233
244
|
if (!isValidEnvName(name) || !environment || typeof environment !== "object" || Array.isArray(environment)) {
|
|
234
245
|
continue;
|
|
235
246
|
}
|
|
236
|
-
const
|
|
237
|
-
if (typeof convexUrl !== "string") continue;
|
|
247
|
+
const entry = environment;
|
|
248
|
+
if (typeof entry.convexUrl !== "string") continue;
|
|
238
249
|
try {
|
|
239
|
-
|
|
250
|
+
const appUrl = typeof entry.appUrl === "string" ? normalizeAppUrl(entry.appUrl) : void 0;
|
|
251
|
+
environments[name] = {
|
|
252
|
+
convexUrl: normalizeConvexUrl(entry.convexUrl),
|
|
253
|
+
...appUrl ? { appUrl } : {}
|
|
254
|
+
};
|
|
240
255
|
} catch {
|
|
241
256
|
}
|
|
242
257
|
}
|
|
243
258
|
}
|
|
259
|
+
environments[DEFAULT_TARGET_NAME] = { convexUrl: DEFAULT_PROD_URL };
|
|
244
260
|
return {
|
|
245
261
|
schemaVersion: 1,
|
|
246
262
|
active: config.active,
|
|
@@ -275,7 +291,7 @@ function resolveEnvConvexUrl(envName) {
|
|
|
275
291
|
if (envName === DEFAULT_TARGET_NAME) return DEFAULT_PROD_URL;
|
|
276
292
|
return null;
|
|
277
293
|
}
|
|
278
|
-
function setActiveEnvironment(name, convexUrl) {
|
|
294
|
+
function setActiveEnvironment(name, convexUrl, appUrl) {
|
|
279
295
|
if (!isValidEnvName(name)) {
|
|
280
296
|
throw new Error(`Invalid FML environment name: ${name}`);
|
|
281
297
|
}
|
|
@@ -285,19 +301,23 @@ function setActiveEnvironment(name, convexUrl) {
|
|
|
285
301
|
active: name,
|
|
286
302
|
environments: {
|
|
287
303
|
...current.environments ?? {},
|
|
288
|
-
[name]: {
|
|
304
|
+
[name]: {
|
|
305
|
+
convexUrl: normalizeConvexUrl(convexUrl),
|
|
306
|
+
...appUrl ? { appUrl: normalizeAppUrl(appUrl) } : {}
|
|
307
|
+
}
|
|
289
308
|
}
|
|
290
309
|
};
|
|
291
310
|
writeEnvConfig(next);
|
|
292
311
|
return next;
|
|
293
312
|
}
|
|
294
313
|
function getActiveEnv() {
|
|
295
|
-
const
|
|
314
|
+
const config = readEnvConfig();
|
|
315
|
+
const name = config.active;
|
|
316
|
+
const stored = config.environments?.[name];
|
|
296
317
|
const override = process.env.FML_CONVEX_URL;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
};
|
|
318
|
+
const convexUrl = override ? normalizeConvexUrl(override) : resolveEnvConvexUrl(name);
|
|
319
|
+
const appUrl = stored?.appUrl && stored.convexUrl === convexUrl ? stored.appUrl : null;
|
|
320
|
+
return { name, convexUrl, appUrl };
|
|
301
321
|
}
|
|
302
322
|
function authStorePathFor(envName) {
|
|
303
323
|
return path2.join(FML_DATA_DIR, `auth.${envName}.json`);
|
|
@@ -311,7 +331,7 @@ function getSiteUrl() {
|
|
|
311
331
|
function getSiteUrlForConvexUrl(convexUrl) {
|
|
312
332
|
const explicit = process.env.CONVEX_SITE_URL;
|
|
313
333
|
if (explicit) return explicit.replace(/\/$/, "");
|
|
314
|
-
return (convexUrl ?? DEFAULT_PROD_URL).replace(
|
|
334
|
+
return (convexUrl ?? DEFAULT_PROD_URL).replace(/\/$/, "");
|
|
315
335
|
}
|
|
316
336
|
|
|
317
337
|
// src/sentry.ts
|
|
@@ -1587,8 +1607,10 @@ export {
|
|
|
1587
1607
|
ensureDirs,
|
|
1588
1608
|
DEFAULT_PROD_URL,
|
|
1589
1609
|
DEFAULT_TARGET_NAME,
|
|
1610
|
+
isHostedBackendUrl,
|
|
1590
1611
|
isValidEnvName,
|
|
1591
1612
|
normalizeConvexUrl,
|
|
1613
|
+
readEnvConfig,
|
|
1592
1614
|
writeEnvConfig,
|
|
1593
1615
|
envConfigExists,
|
|
1594
1616
|
resolveEnvConvexUrl,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OBSERVER_SERVICE_NAME
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5TOOBX7I.js";
|
|
4
4
|
import {
|
|
5
5
|
FML_OBSERVER_LOCK_FILE,
|
|
6
6
|
FML_OBSERVER_PORT,
|
|
7
7
|
FML_OBSERVER_STATE_FILE,
|
|
8
8
|
Sentry
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-B3H2YWPJ.js";
|
|
10
10
|
|
|
11
11
|
// src/observer/state.ts
|
|
12
12
|
import { randomUUID } from "crypto";
|
|
@@ -990,7 +990,7 @@ var PACKAGE_NAME = "@fml-inc/fml";
|
|
|
990
990
|
var UPDATE_TIMEOUT_MS = 12e4;
|
|
991
991
|
var SETUP_TIMEOUT_MS = 3e5;
|
|
992
992
|
function getCurrentVersion() {
|
|
993
|
-
return true ? "0.8.6
|
|
993
|
+
return true ? "0.8.6+f7c7191d" : "unknown";
|
|
994
994
|
}
|
|
995
995
|
function parseVersion(version) {
|
|
996
996
|
const match = SEMVER_PATTERN.exec(version);
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getSelectedOrg,
|
|
8
8
|
getSiteUrlForConvexUrl,
|
|
9
9
|
getValidToken
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-B3H2YWPJ.js";
|
|
11
11
|
|
|
12
12
|
// src/fml-client.ts
|
|
13
13
|
var LOGIN_EXPIRED_MESSAGE = "Authentication expired. Run `fml login` to sign in again, then restart Claude Code.";
|
|
@@ -79,7 +79,7 @@ function createFmlClient(token, options = {}) {
|
|
|
79
79
|
const repo = resolveRepoFromCwd(process.cwd());
|
|
80
80
|
if (repo) body.repo = repo.repo;
|
|
81
81
|
if (isServiceToken) {
|
|
82
|
-
const { readTokens, SERVICE_TOKEN_LOGIN_USER_ID } = await import("./token-store-
|
|
82
|
+
const { readTokens, SERVICE_TOKEN_LOGIN_USER_ID } = await import("./token-store-ORR5MIJL.js");
|
|
83
83
|
const stored = readTokens(options.envName);
|
|
84
84
|
const storedUserExternalId = stored?.tokenType === "service" && stored.user.id !== SERVICE_TOKEN_LOGIN_USER_ID ? stored.user.id : void 0;
|
|
85
85
|
const userExternalId = process.env.FML_USER_EXTERNAL_ID ?? storedUserExternalId;
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createFmlClient,
|
|
4
4
|
getAuthenticatedClient
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LOJPIJZW.js";
|
|
6
6
|
import {
|
|
7
7
|
OBSERVER_HEARTBEAT_STALE_MS,
|
|
8
8
|
execBinSync,
|
|
@@ -13,13 +13,13 @@ import {
|
|
|
13
13
|
readObserverStateStatus,
|
|
14
14
|
removeObserverStateIfOwned,
|
|
15
15
|
resolveBin
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-E2MATWOU.js";
|
|
17
17
|
import {
|
|
18
18
|
readJsonFile,
|
|
19
19
|
setHookCaptureDisabled,
|
|
20
20
|
writeJsonFile,
|
|
21
21
|
writeTextFileAtomic
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-2DQQXBWM.js";
|
|
23
23
|
import {
|
|
24
24
|
CODEX_HOOK_EVENTS,
|
|
25
25
|
GEMINI_HOOK_EVENTS,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
isObserverHealth,
|
|
28
28
|
readHookInboxStatus,
|
|
29
29
|
readObserverAuthToken
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-5TOOBX7I.js";
|
|
31
31
|
import "./chunk-7V7G7NVF.js";
|
|
32
32
|
import {
|
|
33
33
|
claudeConfigDirectory,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
initializeSyncSettings,
|
|
38
38
|
resolvePackageRoot,
|
|
39
39
|
runRawSyncOnce
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-V2XC7JTB.js";
|
|
41
41
|
import {
|
|
42
42
|
DEFAULT_PROD_URL,
|
|
43
43
|
DEFAULT_TARGET_NAME,
|
|
@@ -68,9 +68,11 @@ import {
|
|
|
68
68
|
getSiteUrlForConvexUrl,
|
|
69
69
|
getValidToken,
|
|
70
70
|
initSentry,
|
|
71
|
+
isHostedBackendUrl,
|
|
71
72
|
isValidEnvName,
|
|
72
73
|
normalizeConvexUrl,
|
|
73
74
|
observerOnlyOverrideWarning,
|
|
75
|
+
readEnvConfig,
|
|
74
76
|
readTokens,
|
|
75
77
|
resolveEnvConvexUrl,
|
|
76
78
|
resolveFmlDefaultDirectories,
|
|
@@ -79,7 +81,7 @@ import {
|
|
|
79
81
|
storeServiceRefreshToken,
|
|
80
82
|
writeEnvConfig,
|
|
81
83
|
writeTokens
|
|
82
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-B3H2YWPJ.js";
|
|
83
85
|
import "./chunk-MLKGABMK.js";
|
|
84
86
|
|
|
85
87
|
// src/cli.ts
|
|
@@ -127,7 +129,7 @@ var POLL_INTERVAL_MS = 50;
|
|
|
127
129
|
var LOG_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
128
130
|
var LOG_ROTATE_FILES = 3;
|
|
129
131
|
function expectedObserverVersion() {
|
|
130
|
-
return true ? "0.8.6
|
|
132
|
+
return true ? "0.8.6+f7c7191d" : "dev";
|
|
131
133
|
}
|
|
132
134
|
function delay(ms) {
|
|
133
135
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -6828,8 +6830,16 @@ async function handleFmlRestart() {
|
|
|
6828
6830
|
import crypto from "crypto";
|
|
6829
6831
|
import http from "http";
|
|
6830
6832
|
async function fetchWorkosLoginConfig(siteUrl) {
|
|
6831
|
-
const
|
|
6832
|
-
const
|
|
6833
|
+
const configUrl = `${siteUrl}/api/auth/config`;
|
|
6834
|
+
const response = await fetch(configUrl);
|
|
6835
|
+
let data;
|
|
6836
|
+
try {
|
|
6837
|
+
data = await response.json();
|
|
6838
|
+
} catch {
|
|
6839
|
+
throw new Error(
|
|
6840
|
+
`${configUrl} did not return JSON (HTTP ${response.status}). Use the FML backend HTTP-actions origin, not the web app URL.`
|
|
6841
|
+
);
|
|
6842
|
+
}
|
|
6833
6843
|
if (!response.ok || data.ok === false || !data.workosClientId) {
|
|
6834
6844
|
throw new Error(data.error ?? `HTTP ${response.status}`);
|
|
6835
6845
|
}
|
|
@@ -7001,14 +7011,6 @@ function startCallbackServer(expectedState) {
|
|
|
7001
7011
|
function sleep(ms) {
|
|
7002
7012
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7003
7013
|
}
|
|
7004
|
-
async function fetchWorkosClientId(siteUrl) {
|
|
7005
|
-
const response = await fetch(`${siteUrl}/api/auth/config`);
|
|
7006
|
-
const data = await response.json();
|
|
7007
|
-
if (!response.ok || data.ok === false || !data.workosClientId) {
|
|
7008
|
-
throw new Error(data.error ?? `HTTP ${response.status}`);
|
|
7009
|
-
}
|
|
7010
|
-
return data.workosClientId;
|
|
7011
|
-
}
|
|
7012
7014
|
function userName(user) {
|
|
7013
7015
|
return [user.first_name, user.last_name].filter(Boolean).join(" ");
|
|
7014
7016
|
}
|
|
@@ -7086,7 +7088,7 @@ async function pollForTokens(clientId, authorization) {
|
|
|
7086
7088
|
throw new Error("Device authorization timed out. Run `fml login` again.");
|
|
7087
7089
|
}
|
|
7088
7090
|
async function deviceLogin(options) {
|
|
7089
|
-
const clientId = await
|
|
7091
|
+
const { clientId } = await fetchWorkosLoginConfig(options.siteUrl);
|
|
7090
7092
|
const authorization = await requestDeviceAuthorization(clientId);
|
|
7091
7093
|
console.log("");
|
|
7092
7094
|
console.log(" Sign in with this code:");
|
|
@@ -7153,14 +7155,78 @@ function resolveGitHubToken() {
|
|
|
7153
7155
|
}
|
|
7154
7156
|
}
|
|
7155
7157
|
|
|
7158
|
+
// src/backend-discovery.ts
|
|
7159
|
+
var DISCOVERY_TIMEOUT_MS = 3e4;
|
|
7160
|
+
var defaultFetch = (input) => fetch(input, { signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS) });
|
|
7161
|
+
async function fetchJsonObject(url, fetchImpl) {
|
|
7162
|
+
let response;
|
|
7163
|
+
try {
|
|
7164
|
+
response = await fetchImpl(url);
|
|
7165
|
+
} catch (error) {
|
|
7166
|
+
const message = error instanceof Error && error.name === "TimeoutError" ? `no response within ${DISCOVERY_TIMEOUT_MS / 1e3}s` : error instanceof Error ? error.message : String(error);
|
|
7167
|
+
throw new Error(`Could not reach ${url}: ${message}`);
|
|
7168
|
+
}
|
|
7169
|
+
let parsed;
|
|
7170
|
+
try {
|
|
7171
|
+
parsed = await response.json();
|
|
7172
|
+
} catch {
|
|
7173
|
+
return null;
|
|
7174
|
+
}
|
|
7175
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
7176
|
+
return null;
|
|
7177
|
+
}
|
|
7178
|
+
return parsed;
|
|
7179
|
+
}
|
|
7180
|
+
async function discoverBackend(inputUrl, fetchImpl = defaultFetch) {
|
|
7181
|
+
const origin = normalizeConvexUrl(inputUrl);
|
|
7182
|
+
const appConfig = await fetchJsonObject(
|
|
7183
|
+
`${origin}/api/cli/config`,
|
|
7184
|
+
fetchImpl
|
|
7185
|
+
);
|
|
7186
|
+
if (appConfig?.ok === true && typeof appConfig.backendUrl === "string") {
|
|
7187
|
+
let backendUrl;
|
|
7188
|
+
try {
|
|
7189
|
+
backendUrl = normalizeConvexUrl(appConfig.backendUrl);
|
|
7190
|
+
} catch {
|
|
7191
|
+
throw new Error(
|
|
7192
|
+
`${origin} advertised an invalid FML backend URL: ${appConfig.backendUrl}`
|
|
7193
|
+
);
|
|
7194
|
+
}
|
|
7195
|
+
return { backendUrl, appUrl: origin };
|
|
7196
|
+
}
|
|
7197
|
+
if (appConfig && (appConfig.service === "fml-app" || appConfig.ok === false) && typeof appConfig.error === "string") {
|
|
7198
|
+
throw new Error(
|
|
7199
|
+
`${origin} could not provide its backend: ${appConfig.error}`
|
|
7200
|
+
);
|
|
7201
|
+
}
|
|
7202
|
+
const authConfig = await fetchJsonObject(
|
|
7203
|
+
`${origin}/api/auth/config`,
|
|
7204
|
+
fetchImpl
|
|
7205
|
+
);
|
|
7206
|
+
if (authConfig?.ok === true && typeof authConfig.workosClientId === "string") {
|
|
7207
|
+
return { backendUrl: origin };
|
|
7208
|
+
}
|
|
7209
|
+
throw new Error(
|
|
7210
|
+
`${origin} is not an FML web app or backend URL. Pass the address you use to open FML in the browser. If that app was deployed before CLI discovery existed, pass its backend HTTP origin instead.`
|
|
7211
|
+
);
|
|
7212
|
+
}
|
|
7213
|
+
|
|
7156
7214
|
// src/commands/login.ts
|
|
7157
|
-
function
|
|
7158
|
-
if (
|
|
7159
|
-
const
|
|
7160
|
-
|
|
7215
|
+
async function resolveLoginEnvironment(deploymentUrl) {
|
|
7216
|
+
if (deploymentUrl) {
|
|
7217
|
+
const discovered = await discoverBackend(deploymentUrl);
|
|
7218
|
+
if (isHostedBackendUrl(discovered.backendUrl)) {
|
|
7219
|
+
return {
|
|
7220
|
+
envName: DEFAULT_TARGET_NAME,
|
|
7221
|
+
siteUrl: getSiteUrlForConvexUrl(DEFAULT_PROD_URL),
|
|
7222
|
+
pendingConvexUrl: DEFAULT_PROD_URL
|
|
7223
|
+
};
|
|
7224
|
+
}
|
|
7161
7225
|
return {
|
|
7162
7226
|
envName: "custom",
|
|
7163
|
-
siteUrl: getSiteUrlForConvexUrl(
|
|
7227
|
+
siteUrl: getSiteUrlForConvexUrl(discovered.backendUrl),
|
|
7228
|
+
pendingConvexUrl: discovered.backendUrl,
|
|
7229
|
+
...discovered.appUrl ? { pendingAppUrl: discovered.appUrl } : {}
|
|
7164
7230
|
};
|
|
7165
7231
|
}
|
|
7166
7232
|
const environment = getActiveEnv();
|
|
@@ -7169,6 +7235,22 @@ function prepareLoginEnvironment(backendUrl) {
|
|
|
7169
7235
|
siteUrl: getSiteUrlForConvexUrl(environment.convexUrl)
|
|
7170
7236
|
};
|
|
7171
7237
|
}
|
|
7238
|
+
function commitLoginEnvironment(environment) {
|
|
7239
|
+
if (environment.pendingConvexUrl) {
|
|
7240
|
+
setActiveEnvironment(
|
|
7241
|
+
environment.envName,
|
|
7242
|
+
environment.pendingConvexUrl,
|
|
7243
|
+
environment.pendingAppUrl
|
|
7244
|
+
);
|
|
7245
|
+
}
|
|
7246
|
+
}
|
|
7247
|
+
function canReuseStoredLogin(stored, environment) {
|
|
7248
|
+
if (stored?.siteUrl) {
|
|
7249
|
+
if (stored.siteUrl === environment.siteUrl) return true;
|
|
7250
|
+
return environment.envName === DEFAULT_TARGET_NAME && isHostedBackendUrl(stored.siteUrl);
|
|
7251
|
+
}
|
|
7252
|
+
return !environment.pendingConvexUrl;
|
|
7253
|
+
}
|
|
7172
7254
|
async function linkGitHubIdentity(environment) {
|
|
7173
7255
|
const token = resolveGitHubToken();
|
|
7174
7256
|
if (!token) {
|
|
@@ -7302,7 +7384,7 @@ async function selectOrg(environment) {
|
|
|
7302
7384
|
}
|
|
7303
7385
|
}
|
|
7304
7386
|
async function runServiceTokenLogin(refreshToken, backendUrl) {
|
|
7305
|
-
const environment =
|
|
7387
|
+
const environment = await resolveLoginEnvironment(backendUrl);
|
|
7306
7388
|
const envName = environment.envName;
|
|
7307
7389
|
if (!isValidEnvName(envName)) {
|
|
7308
7390
|
throw new Error(
|
|
@@ -7318,6 +7400,7 @@ async function runServiceTokenLogin(refreshToken, backendUrl) {
|
|
|
7318
7400
|
if (!ok) {
|
|
7319
7401
|
throw new Error("Service token login failed.");
|
|
7320
7402
|
}
|
|
7403
|
+
commitLoginEnvironment(environment);
|
|
7321
7404
|
await selectOrg(environment);
|
|
7322
7405
|
console.log("Logged in with FML service token.");
|
|
7323
7406
|
console.log(
|
|
@@ -7340,11 +7423,14 @@ async function handleServiceTokenLogin(refreshToken, backendUrl) {
|
|
|
7340
7423
|
}
|
|
7341
7424
|
}
|
|
7342
7425
|
async function runInteractiveLogin(opts = {}) {
|
|
7343
|
-
const environment =
|
|
7426
|
+
const environment = await resolveLoginEnvironment(opts.backendUrl);
|
|
7344
7427
|
const envName = environment.envName;
|
|
7345
7428
|
const stored = readTokens(envName);
|
|
7346
|
-
|
|
7347
|
-
|
|
7429
|
+
let existingToken = null;
|
|
7430
|
+
if (canReuseStoredLogin(stored, environment)) {
|
|
7431
|
+
commitLoginEnvironment(environment);
|
|
7432
|
+
existingToken = await getValidToken({ env: envName });
|
|
7433
|
+
}
|
|
7348
7434
|
if (existingToken) {
|
|
7349
7435
|
if (stored?.tokenType === "service") {
|
|
7350
7436
|
const label = stored.user.id === SERVICE_TOKEN_LOGIN_USER_ID ? "a service token" : `${stored.user.name} (${stored.user.email})`;
|
|
@@ -7366,6 +7452,7 @@ async function runInteractiveLogin(opts = {}) {
|
|
|
7366
7452
|
} else {
|
|
7367
7453
|
result = await login(environment);
|
|
7368
7454
|
}
|
|
7455
|
+
commitLoginEnvironment(environment);
|
|
7369
7456
|
console.log(`Logged in as ${result.name} (${result.email})`);
|
|
7370
7457
|
await linkGitHubIdentity(environment);
|
|
7371
7458
|
await selectOrg(environment);
|
|
@@ -7393,7 +7480,7 @@ async function handleLogin(opts) {
|
|
|
7393
7480
|
var defaultDependencies = {
|
|
7394
7481
|
install: () => handleInstall(),
|
|
7395
7482
|
getActiveToken: () => getValidToken({ env: getActiveEnv().name }),
|
|
7396
|
-
login: () => runInteractiveLogin(),
|
|
7483
|
+
login: (options) => runInteractiveLogin(options),
|
|
7397
7484
|
stop: () => handleFmlStop(),
|
|
7398
7485
|
start: () => handleFmlStart()
|
|
7399
7486
|
};
|
|
@@ -7408,15 +7495,25 @@ async function handleSetup(dependencies = defaultDependencies, options = {}) {
|
|
|
7408
7495
|
if (process.exitCode) {
|
|
7409
7496
|
throw new Error("FML setup cannot run after an earlier command failure.");
|
|
7410
7497
|
}
|
|
7498
|
+
if (options.backendUrl && options.nonInteractive) {
|
|
7499
|
+
throw new Error(
|
|
7500
|
+
"A backend URL requires interactive login; omit --non-interactive."
|
|
7501
|
+
);
|
|
7502
|
+
}
|
|
7411
7503
|
console.log("Setting up FML...");
|
|
7412
7504
|
await runStep("integration installation", dependencies.install);
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
} else if (options.nonInteractive) {
|
|
7417
|
-
console.log("Not signed in; skipping login (non-interactive).");
|
|
7505
|
+
if (options.backendUrl) {
|
|
7506
|
+
const backendUrl = options.backendUrl;
|
|
7507
|
+
await runStep("login", () => dependencies.login({ backendUrl }));
|
|
7418
7508
|
} else {
|
|
7419
|
-
await
|
|
7509
|
+
const token = await dependencies.getActiveToken();
|
|
7510
|
+
if (token) {
|
|
7511
|
+
console.log("Already signed in.");
|
|
7512
|
+
} else if (options.nonInteractive) {
|
|
7513
|
+
console.log("Not signed in; skipping login (non-interactive).");
|
|
7514
|
+
} else {
|
|
7515
|
+
await runStep("login", () => dependencies.login());
|
|
7516
|
+
}
|
|
7420
7517
|
}
|
|
7421
7518
|
await runStep("observer stop", dependencies.stop);
|
|
7422
7519
|
await runStep("observer start", dependencies.start);
|
|
@@ -7927,9 +8024,12 @@ async function handleOrg(slug) {
|
|
|
7927
8024
|
|
|
7928
8025
|
// src/commands/open.ts
|
|
7929
8026
|
var DEFAULT_APP_BASE_URL = "https://app.fml.inc";
|
|
7930
|
-
function appBaseUrl() {
|
|
8027
|
+
function appBaseUrl(environmentAppUrl) {
|
|
7931
8028
|
const configured = process.env.FML_APP_URL?.trim();
|
|
7932
|
-
return (configured || DEFAULT_APP_BASE_URL).replace(
|
|
8029
|
+
return (configured || environmentAppUrl || DEFAULT_APP_BASE_URL).replace(
|
|
8030
|
+
/\/+$/,
|
|
8031
|
+
""
|
|
8032
|
+
);
|
|
7933
8033
|
}
|
|
7934
8034
|
async function handleOpen(opts) {
|
|
7935
8035
|
const environment = getActiveEnv();
|
|
@@ -7957,7 +8057,7 @@ async function handleOpen(opts) {
|
|
|
7957
8057
|
);
|
|
7958
8058
|
slug = "";
|
|
7959
8059
|
}
|
|
7960
|
-
const baseUrl = appBaseUrl();
|
|
8060
|
+
const baseUrl = appBaseUrl(environment.appUrl);
|
|
7961
8061
|
const url = slug ? `${baseUrl}/${slug}` : baseUrl;
|
|
7962
8062
|
if (opts.json) {
|
|
7963
8063
|
console.log(JSON.stringify({ url }));
|
|
@@ -8246,22 +8346,35 @@ async function handleStatus() {
|
|
|
8246
8346
|
|
|
8247
8347
|
// src/commands/env.ts
|
|
8248
8348
|
function handleEnvShow() {
|
|
8249
|
-
const { name, convexUrl } = getActiveEnv();
|
|
8349
|
+
const { name, convexUrl, appUrl } = getActiveEnv();
|
|
8250
8350
|
console.log(`Environment: ${name}`);
|
|
8251
8351
|
console.log(` Service URL: ${convexUrl ?? "not configured"}`);
|
|
8352
|
+
if (appUrl) console.log(` App URL: ${appUrl}`);
|
|
8252
8353
|
}
|
|
8253
|
-
function handleEnvSwitch(target2) {
|
|
8354
|
+
async function handleEnvSwitch(target2) {
|
|
8254
8355
|
let name = target2;
|
|
8255
8356
|
let convexUrl = null;
|
|
8357
|
+
let appUrl;
|
|
8256
8358
|
try {
|
|
8257
8359
|
if (/^https?:\/\//.test(target2)) {
|
|
8258
|
-
|
|
8259
|
-
|
|
8360
|
+
const discovered = await discoverBackend(target2);
|
|
8361
|
+
if (isHostedBackendUrl(discovered.backendUrl)) {
|
|
8362
|
+
name = DEFAULT_TARGET_NAME;
|
|
8363
|
+
convexUrl = DEFAULT_PROD_URL;
|
|
8364
|
+
} else {
|
|
8365
|
+
name = "custom";
|
|
8366
|
+
convexUrl = discovered.backendUrl;
|
|
8367
|
+
appUrl = discovered.appUrl;
|
|
8368
|
+
}
|
|
8260
8369
|
} else {
|
|
8261
8370
|
if (!isValidEnvName(target2)) {
|
|
8262
8371
|
throw new Error(`Invalid FML environment name: ${target2}`);
|
|
8263
8372
|
}
|
|
8264
8373
|
convexUrl = process.env.FML_CONVEX_URL ? normalizeConvexUrl(process.env.FML_CONVEX_URL) : resolveEnvConvexUrl(target2);
|
|
8374
|
+
const stored = readEnvConfig().environments?.[target2];
|
|
8375
|
+
if (stored?.appUrl && stored.convexUrl === convexUrl) {
|
|
8376
|
+
appUrl = stored.appUrl;
|
|
8377
|
+
}
|
|
8265
8378
|
}
|
|
8266
8379
|
} catch (error) {
|
|
8267
8380
|
console.error(
|
|
@@ -8273,14 +8386,15 @@ function handleEnvSwitch(target2) {
|
|
|
8273
8386
|
if (!convexUrl) {
|
|
8274
8387
|
console.error(`Environment ${name} has no configured service URL.`);
|
|
8275
8388
|
console.error(
|
|
8276
|
-
`Set FML_CONVEX_URL=https://<
|
|
8389
|
+
`Set FML_CONVEX_URL=https://<backend-origin> and run \`fml env ${name}\` again.`
|
|
8277
8390
|
);
|
|
8278
8391
|
process.exitCode = 1;
|
|
8279
8392
|
return;
|
|
8280
8393
|
}
|
|
8281
|
-
setActiveEnvironment(name, convexUrl);
|
|
8394
|
+
setActiveEnvironment(name, convexUrl, appUrl);
|
|
8282
8395
|
console.log(`Environment switched to ${name}.`);
|
|
8283
8396
|
console.log(`Service URL: ${convexUrl}`);
|
|
8397
|
+
if (appUrl) console.log(`App URL: ${appUrl}`);
|
|
8284
8398
|
console.log("CLI commands and agent activity sync now use this environment.");
|
|
8285
8399
|
console.log(
|
|
8286
8400
|
"Start a new agent session to use the new environment and credentials."
|
|
@@ -8841,7 +8955,7 @@ async function handleConfigDetail(opts) {
|
|
|
8841
8955
|
// src/commands/tools.ts
|
|
8842
8956
|
import { readFileSync } from "fs";
|
|
8843
8957
|
import path28 from "path";
|
|
8844
|
-
var pluginVersion = true ? "0.8.6
|
|
8958
|
+
var pluginVersion = true ? "0.8.6+f7c7191d" : void 0;
|
|
8845
8959
|
async function getApi() {
|
|
8846
8960
|
const api = await getAuthenticatedClient();
|
|
8847
8961
|
if (!api) {
|
|
@@ -8998,7 +9112,7 @@ if (process.argv.length <= 2 || process.argv.includes("--help") || process.argv.
|
|
|
8998
9112
|
printBanner();
|
|
8999
9113
|
}
|
|
9000
9114
|
var program = new Command().name("fml").description("FML CLI and agent tools").version(
|
|
9001
|
-
true ? "0.8.6
|
|
9115
|
+
true ? "0.8.6+f7c7191d" : "dev"
|
|
9002
9116
|
);
|
|
9003
9117
|
function formatCommandInventory(cmd, prefix = "") {
|
|
9004
9118
|
const name = prefix ? `${prefix} ${cmd.name()}` : cmd.name();
|
|
@@ -9027,13 +9141,19 @@ tools.command("call").description("Invoke a backend tool by name with JSON args"
|
|
|
9027
9141
|
program.command("mcp-server", { hidden: true }).description("Run the FML MCP server on stdio").action(async () => {
|
|
9028
9142
|
await import("./mcp/server.js");
|
|
9029
9143
|
});
|
|
9030
|
-
program.command("setup").description("Install integrations, sign in if needed, and start FML").
|
|
9144
|
+
program.command("setup").description("Install integrations, sign in if needed, and start FML").argument(
|
|
9145
|
+
"[backend-url]",
|
|
9146
|
+
"Self-hosted FML app or backend URL (saved as the active custom environment)"
|
|
9147
|
+
).addOption(
|
|
9031
9148
|
new Option(
|
|
9032
9149
|
"--non-interactive",
|
|
9033
9150
|
"Skip interactive login (internal)"
|
|
9034
9151
|
).hideHelp()
|
|
9035
9152
|
).action(
|
|
9036
|
-
(opts) => handleSetup(void 0, {
|
|
9153
|
+
(backendUrl, opts) => handleSetup(void 0, {
|
|
9154
|
+
nonInteractive: Boolean(opts.nonInteractive),
|
|
9155
|
+
backendUrl
|
|
9156
|
+
})
|
|
9037
9157
|
);
|
|
9038
9158
|
program.command("install").description("Register FML agent integrations and the MCP server").action(() => handleInstall());
|
|
9039
9159
|
program.command("uninstall").description("Remove FML agent integrations and optionally local data").option("--purge", "Also remove all data, logs, and auth tokens").option("-y, --yes", "Skip the purge confirmation prompt").action(
|
|
@@ -9049,7 +9169,7 @@ program.command("update").description("Update fml when a newer release is availa
|
|
|
9049
9169
|
);
|
|
9050
9170
|
program.command("login").description("Sign in to your FML account").argument(
|
|
9051
9171
|
"[backend-url]",
|
|
9052
|
-
"Self-hosted FML backend URL (saved as the active custom environment)"
|
|
9172
|
+
"Self-hosted FML app or backend URL (saved as the active custom environment)"
|
|
9053
9173
|
).option("--device", "Use device authorization flow (no browser needed)").option(
|
|
9054
9174
|
"--service-token",
|
|
9055
9175
|
"Sign in with an org service refresh token (prompts for fml_srt_*)"
|
|
@@ -9061,8 +9181,8 @@ program.command("org").description("Show or select organization").argument("[slu
|
|
|
9061
9181
|
program.command("status").description("Show auth, environment, and raw sync watermarks").action(() => handleStatus());
|
|
9062
9182
|
program.command("doctor").description("Check FML configuration, agent activity sync, and connectivity").option("--json", "Output as JSON").action((opts) => handleDoctor(opts));
|
|
9063
9183
|
program.command("open").description("Open FML dashboard in browser").option("--json", "Output URL as JSON instead of opening browser").action((opts) => handleOpen(opts));
|
|
9064
|
-
program.command("env").description("Show or switch FML backend environment").argument("[target]", "Environment name or backend URL").action((target2) => {
|
|
9065
|
-
if (target2) handleEnvSwitch(target2);
|
|
9184
|
+
program.command("env").description("Show or switch FML backend environment").argument("[target]", "Environment name, FML app URL, or backend URL").action(async (target2) => {
|
|
9185
|
+
if (target2) await handleEnvSwitch(target2);
|
|
9066
9186
|
else handleEnvShow();
|
|
9067
9187
|
});
|
|
9068
9188
|
program.command("start").description("Start the local observer and continuous agent activity sync").action(() => handleFmlStart());
|
package/dist/hook-handler.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
hookCaptureIsDisabled
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2DQQXBWM.js";
|
|
5
5
|
import {
|
|
6
6
|
getActiveHookDestinationBinding
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-PJWMSHHZ.js";
|
|
8
8
|
import {
|
|
9
9
|
SHELL_TOOL_NAMES,
|
|
10
10
|
createHookInboxEntry,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
normalizeObserverHookCapture,
|
|
13
13
|
persistHookInboxEntry,
|
|
14
14
|
readObserverAuthToken
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-5TOOBX7I.js";
|
|
16
16
|
import {
|
|
17
17
|
resolveRepositoryRootFromCwd,
|
|
18
18
|
resolveRepositorySlugFromCwd
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
FML_OBSERVER_AUTH_TOKEN_FILE,
|
|
24
24
|
FML_OBSERVER_ENDPOINT_FILE,
|
|
25
25
|
getValidToken
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-B3H2YWPJ.js";
|
|
27
27
|
import "./chunk-MLKGABMK.js";
|
|
28
28
|
|
|
29
29
|
// src/hooks/handler.ts
|
package/dist/mcp/server.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createFmlClient,
|
|
4
4
|
getAuthenticatedClient
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-LOJPIJZW.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveRepoFromCwd
|
|
8
8
|
} from "../chunk-7V7G7NVF.js";
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
getValidToken,
|
|
18
18
|
initSentry,
|
|
19
19
|
readTokens
|
|
20
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-B3H2YWPJ.js";
|
|
21
21
|
import "../chunk-MLKGABMK.js";
|
|
22
22
|
|
|
23
23
|
// src/mcp/server.ts
|
package/dist/observer-server.js
CHANGED
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
removeObserverStateIfOwned,
|
|
12
12
|
resolveBin,
|
|
13
13
|
updateObserverState
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-E2MATWOU.js";
|
|
15
15
|
import {
|
|
16
16
|
createHookSyncLoop,
|
|
17
17
|
getActiveHookDestinationBinding
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-PJWMSHHZ.js";
|
|
19
19
|
import {
|
|
20
20
|
OBSERVER_PROTOCOL_VERSION,
|
|
21
21
|
OBSERVER_SERVICE_NAME,
|
|
@@ -30,15 +30,15 @@ import {
|
|
|
30
30
|
parseHookInboxMetadata,
|
|
31
31
|
readHookInboxStatusAsync,
|
|
32
32
|
retireHookInboxEntry
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-5TOOBX7I.js";
|
|
34
34
|
import "./chunk-7V7G7NVF.js";
|
|
35
35
|
import {
|
|
36
36
|
ObserverSyncCycleAbortedError,
|
|
37
37
|
runObserverSyncCycleSubprocess
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-YFHZJPTC.js";
|
|
39
39
|
import {
|
|
40
40
|
createCliRawSync
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-V2XC7JTB.js";
|
|
42
42
|
import {
|
|
43
43
|
FML_OBSERVER_AUTH_TOKEN_FILE,
|
|
44
44
|
FML_OBSERVER_ENDPOINT_FILE,
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
getSyncDestinationAuthBinding,
|
|
57
57
|
getValidToken,
|
|
58
58
|
observerOnlyOverrideWarning
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-B3H2YWPJ.js";
|
|
60
60
|
import "./chunk-MLKGABMK.js";
|
|
61
61
|
|
|
62
62
|
// src/observer-server.ts
|
|
@@ -1480,7 +1480,7 @@ var hookRejectionStatus = () => ({
|
|
|
1480
1480
|
...lastRejectedReason !== void 0 ? { lastRejectedReason } : {},
|
|
1481
1481
|
...lastRejectedTarget !== void 0 ? { lastRejectedTarget } : {}
|
|
1482
1482
|
});
|
|
1483
|
-
var packageVersion = true ? "0.8.6
|
|
1483
|
+
var packageVersion = true ? "0.8.6+f7c7191d" : "dev";
|
|
1484
1484
|
var health = () => ({
|
|
1485
1485
|
status: "ok",
|
|
1486
1486
|
service: OBSERVER_SERVICE_NAME,
|
package/dist/pi/extension.js
CHANGED
|
@@ -853,11 +853,7 @@ var FML_HOOK_CAPTURE_DISABLED_FILE = path3.join(
|
|
|
853
853
|
);
|
|
854
854
|
|
|
855
855
|
// src/config.ts
|
|
856
|
-
var DEFAULT_PROD_URL = "https://
|
|
857
|
-
var DEFAULT_SYNC_URL = DEFAULT_PROD_URL.replace(
|
|
858
|
-
".convex.cloud",
|
|
859
|
-
".convex.site"
|
|
860
|
-
);
|
|
856
|
+
var DEFAULT_PROD_URL = "https://api.fml.inc";
|
|
861
857
|
var DEFAULT_TARGET_NAME = "fml";
|
|
862
858
|
var ENV_CONFIG_PATH = path4.join(FML_DATA_DIR, "env.json");
|
|
863
859
|
var ENV_NAME_RE = /^[A-Za-z0-9_-]+$/;
|
|
@@ -872,7 +868,10 @@ function normalizeConvexUrl(value) {
|
|
|
872
868
|
"FML environment URL must be HTTPS (HTTP is allowed only for loopback) with no path, credentials, query, or fragment"
|
|
873
869
|
);
|
|
874
870
|
}
|
|
875
|
-
return
|
|
871
|
+
return url.origin;
|
|
872
|
+
}
|
|
873
|
+
function normalizeAppUrl(value) {
|
|
874
|
+
return normalizeConvexUrl(value);
|
|
876
875
|
}
|
|
877
876
|
function readEnvConfig() {
|
|
878
877
|
try {
|
|
@@ -894,14 +893,19 @@ function readEnvConfig() {
|
|
|
894
893
|
if (!isValidEnvName(name) || !environment || typeof environment !== "object" || Array.isArray(environment)) {
|
|
895
894
|
continue;
|
|
896
895
|
}
|
|
897
|
-
const
|
|
898
|
-
if (typeof convexUrl !== "string") continue;
|
|
896
|
+
const entry = environment;
|
|
897
|
+
if (typeof entry.convexUrl !== "string") continue;
|
|
899
898
|
try {
|
|
900
|
-
|
|
899
|
+
const appUrl = typeof entry.appUrl === "string" ? normalizeAppUrl(entry.appUrl) : void 0;
|
|
900
|
+
environments[name] = {
|
|
901
|
+
convexUrl: normalizeConvexUrl(entry.convexUrl),
|
|
902
|
+
...appUrl ? { appUrl } : {}
|
|
903
|
+
};
|
|
901
904
|
} catch {
|
|
902
905
|
}
|
|
903
906
|
}
|
|
904
907
|
}
|
|
908
|
+
environments[DEFAULT_TARGET_NAME] = { convexUrl: DEFAULT_PROD_URL };
|
|
905
909
|
return {
|
|
906
910
|
schemaVersion: 1,
|
|
907
911
|
active: config.active,
|
|
@@ -924,12 +928,13 @@ function resolveEnvConvexUrl(envName) {
|
|
|
924
928
|
return null;
|
|
925
929
|
}
|
|
926
930
|
function getActiveEnv() {
|
|
927
|
-
const
|
|
931
|
+
const config = readEnvConfig();
|
|
932
|
+
const name = config.active;
|
|
933
|
+
const stored = config.environments?.[name];
|
|
928
934
|
const override = process.env.FML_CONVEX_URL;
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
};
|
|
935
|
+
const convexUrl = override ? normalizeConvexUrl(override) : resolveEnvConvexUrl(name);
|
|
936
|
+
const appUrl = stored?.appUrl && stored.convexUrl === convexUrl ? stored.appUrl : null;
|
|
937
|
+
return { name, convexUrl, appUrl };
|
|
933
938
|
}
|
|
934
939
|
function authStorePathFor(envName) {
|
|
935
940
|
return path4.join(FML_DATA_DIR, `auth.${envName}.json`);
|
|
@@ -939,7 +944,7 @@ var WORKOS_API_URL = "https://api.workos.com";
|
|
|
939
944
|
function getSiteUrlForConvexUrl(convexUrl) {
|
|
940
945
|
const explicit = process.env.CONVEX_SITE_URL;
|
|
941
946
|
if (explicit) return explicit.replace(/\/$/, "");
|
|
942
|
-
return (convexUrl ?? DEFAULT_PROD_URL).replace(
|
|
947
|
+
return (convexUrl ?? DEFAULT_PROD_URL).replace(/\/$/, "");
|
|
943
948
|
}
|
|
944
949
|
|
|
945
950
|
// src/sentry.ts
|
package/dist/sync-cycle.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runObserverSyncCycle
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-YFHZJPTC.js";
|
|
5
|
+
import "./chunk-V2XC7JTB.js";
|
|
6
|
+
import "./chunk-B3H2YWPJ.js";
|
|
7
7
|
import "./chunk-MLKGABMK.js";
|
|
8
8
|
|
|
9
9
|
// src/sync-cycle.ts
|