@fml-inc/fml 0.8.5 → 0.8.6-rc.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/.claude-plugin/plugin.json +1 -1
- package/README.md +20 -5
- package/dist/{chunk-732O7ISN.js → chunk-3T5UCGBR.js} +1 -1
- package/dist/{chunk-IIGTUGO5.js → chunk-FGR7SHV7.js} +1 -1
- package/dist/{chunk-VOSPLAYR.js → chunk-GQ2WVOGY.js} +3 -3
- package/dist/{chunk-ZGA57JPY.js → chunk-GST2GTOC.js} +1 -1
- package/dist/{chunk-LWOINL4K.js → chunk-JEZPS7F5.js} +1 -1
- package/dist/{chunk-ZBSC57CW.js → chunk-KWCFT54L.js} +3 -2
- package/dist/{chunk-P4HOUZXC.js → chunk-RZ5LWWRO.js} +2 -2
- package/dist/{chunk-T3ZFT3QP.js → chunk-Z2LWDZ6Z.js} +1 -1
- package/dist/cli.js +52 -30
- package/dist/hook-handler.js +4 -4
- package/dist/mcp/server.js +2 -2
- package/dist/observer-server.js +53 -17
- package/dist/pi/extension.js +1 -1
- package/dist/sync-cycle.js +3 -3
- package/dist/{token-store-QYXUL4NG.js → token-store-TEPDSK2A.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,20 @@ npm install --global @fml-inc/fml
|
|
|
25
25
|
fml setup
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
For a customer-hosted deployment, pass its public backend (Convex HTTP
|
|
29
|
+
actions) origin directly to login. The CLI validates and saves the URL as the
|
|
30
|
+
active `custom` environment before authenticating, so later CLI and observer
|
|
31
|
+
traffic uses the same deployment:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
fml login https://actions.fml.example.com
|
|
35
|
+
# Headless alternative:
|
|
36
|
+
fml login https://actions.fml.example.com --device
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The URL must be an HTTPS origin with no path, query, credentials, or fragment.
|
|
40
|
+
Plain HTTP is accepted only for loopback development servers.
|
|
41
|
+
|
|
28
42
|
Run `fml update` to check for and install a newer global package with npm. It
|
|
29
43
|
reports the version installed and refreshes FML setup automatically. Stable
|
|
30
44
|
releases stay on npm's `latest` channel; prerelease versions stay on `next`.
|
|
@@ -243,10 +257,11 @@ modes. An existing caller-supplied state directory retains its directory mode.
|
|
|
243
257
|
## Automatic updates
|
|
244
258
|
|
|
245
259
|
While the observer is running it checks npm for a newer FML release about once
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
260
|
+
a day (with jitter). A session-start hook also requests a check, limited to one
|
|
261
|
+
session-start check per hour. When a newer release exists, the observer applies
|
|
262
|
+
it by running `fml update` in the background: `npm install --global` followed by
|
|
263
|
+
`fml setup`, which restarts the observer onto the new version. Output from that
|
|
264
|
+
background update is written to `update.log` in the FML log directory.
|
|
250
265
|
|
|
251
266
|
Auto-update is on by default. To disable it, set `FML_AUTO_UPDATE=off` and
|
|
252
267
|
restart the observer so it picks up the change:
|
|
@@ -302,7 +317,7 @@ fml start Start the local observer and continuous raw sync
|
|
|
302
317
|
fml restart Stop and start the local observer
|
|
303
318
|
fml stop Stop the local observer and disable raw sync
|
|
304
319
|
|
|
305
|
-
fml login
|
|
320
|
+
fml login [backend-url] Sign in to hosted FML or a customer-hosted backend
|
|
306
321
|
fml logout Clear stored credentials
|
|
307
322
|
fml org [slug] Show or select an organization
|
|
308
323
|
fml env [name-or-url] Show or select a backend environment
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OBSERVER_SERVICE_NAME
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3T5UCGBR.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-KWCFT54L.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.
|
|
993
|
+
return true ? "0.8.6-rc.2+bda7cc0a" : "unknown";
|
|
994
994
|
}
|
|
995
995
|
function parseVersion(version) {
|
|
996
996
|
const match = SEMVER_PATTERN.exec(version);
|
|
@@ -454,7 +454,7 @@ function parseStoredAuthShape(parsed) {
|
|
|
454
454
|
}
|
|
455
455
|
const auth = parsed;
|
|
456
456
|
const user = auth.user;
|
|
457
|
-
if (typeof auth.accessToken !== "string" || typeof auth.refreshToken !== "string" || typeof auth.expiresAt !== "number" || !Number.isFinite(auth.expiresAt) || !user || typeof user.id !== "string" || typeof user.email !== "string" || typeof user.name !== "string" || auth.orgId !== void 0 && typeof auth.orgId !== "string" || auth.orgSlug !== void 0 && typeof auth.orgSlug !== "string" || auth.workosClientId !== void 0 && typeof auth.workosClientId !== "string" || auth.tokenType !== void 0 && auth.tokenType !== "oauth" && auth.tokenType !== "service" || auth.refreshInvalidAt !== void 0 && (typeof auth.refreshInvalidAt !== "number" || !Number.isFinite(auth.refreshInvalidAt))) {
|
|
457
|
+
if (typeof auth.accessToken !== "string" || typeof auth.refreshToken !== "string" || typeof auth.expiresAt !== "number" || !Number.isFinite(auth.expiresAt) || !user || typeof user.id !== "string" || typeof user.email !== "string" || typeof user.name !== "string" || auth.orgId !== void 0 && typeof auth.orgId !== "string" || auth.orgSlug !== void 0 && typeof auth.orgSlug !== "string" || auth.workosClientId !== void 0 && typeof auth.workosClientId !== "string" || auth.siteUrl !== void 0 && typeof auth.siteUrl !== "string" || auth.tokenType !== void 0 && auth.tokenType !== "oauth" && auth.tokenType !== "service" || auth.refreshInvalidAt !== void 0 && (typeof auth.refreshInvalidAt !== "number" || !Number.isFinite(auth.refreshInvalidAt))) {
|
|
458
458
|
return null;
|
|
459
459
|
}
|
|
460
460
|
return auth;
|
|
@@ -1314,7 +1314,8 @@ async function storeServiceRefreshToken(refreshToken2, opts) {
|
|
|
1314
1314
|
email: "service-token",
|
|
1315
1315
|
name: "FML service token"
|
|
1316
1316
|
},
|
|
1317
|
-
tokenType: "service"
|
|
1317
|
+
tokenType: "service",
|
|
1318
|
+
...opts?.siteUrl ? { siteUrl: opts.siteUrl } : {}
|
|
1318
1319
|
},
|
|
1319
1320
|
envName
|
|
1320
1321
|
);
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getSelectedOrg,
|
|
8
8
|
getSiteUrlForConvexUrl,
|
|
9
9
|
getValidToken
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-KWCFT54L.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-TEPDSK2A.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-RZ5LWWRO.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-GQ2WVOGY.js";
|
|
17
17
|
import {
|
|
18
18
|
readJsonFile,
|
|
19
19
|
setHookCaptureDisabled,
|
|
20
20
|
writeJsonFile,
|
|
21
21
|
writeTextFileAtomic
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-FGR7SHV7.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-3T5UCGBR.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-Z2LWDZ6Z.js";
|
|
41
41
|
import {
|
|
42
42
|
DEFAULT_PROD_URL,
|
|
43
43
|
DEFAULT_TARGET_NAME,
|
|
@@ -79,7 +79,7 @@ import {
|
|
|
79
79
|
storeServiceRefreshToken,
|
|
80
80
|
writeEnvConfig,
|
|
81
81
|
writeTokens
|
|
82
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-KWCFT54L.js";
|
|
83
83
|
import "./chunk-MLKGABMK.js";
|
|
84
84
|
|
|
85
85
|
// src/cli.ts
|
|
@@ -127,7 +127,7 @@ var POLL_INTERVAL_MS = 50;
|
|
|
127
127
|
var LOG_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
128
128
|
var LOG_ROTATE_FILES = 3;
|
|
129
129
|
function expectedObserverVersion() {
|
|
130
|
-
return true ? "0.8.
|
|
130
|
+
return true ? "0.8.6-rc.2+bda7cc0a" : "dev";
|
|
131
131
|
}
|
|
132
132
|
function delay(ms) {
|
|
133
133
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -6827,13 +6827,17 @@ async function handleFmlRestart() {
|
|
|
6827
6827
|
// src/auth/oauth.ts
|
|
6828
6828
|
import crypto from "crypto";
|
|
6829
6829
|
import http from "http";
|
|
6830
|
-
async function
|
|
6830
|
+
async function fetchWorkosLoginConfig(siteUrl) {
|
|
6831
6831
|
const response = await fetch(`${siteUrl}/api/auth/config`);
|
|
6832
6832
|
const data = await response.json();
|
|
6833
6833
|
if (!response.ok || data.ok === false || !data.workosClientId) {
|
|
6834
6834
|
throw new Error(data.error ?? `HTTP ${response.status}`);
|
|
6835
6835
|
}
|
|
6836
|
-
|
|
6836
|
+
const authUrl = new URL(data.workosAuthUrl ?? WORKOS_AUTH_URL);
|
|
6837
|
+
if (authUrl.protocol !== "https:" || authUrl.username || authUrl.password || authUrl.pathname !== "/" || authUrl.search || authUrl.hash) {
|
|
6838
|
+
throw new Error("FML backend returned an invalid WorkOS authorization URL");
|
|
6839
|
+
}
|
|
6840
|
+
return { clientId: data.workosClientId, authUrl: authUrl.origin };
|
|
6837
6841
|
}
|
|
6838
6842
|
async function canOpenBrowser() {
|
|
6839
6843
|
if (process.env.FML_DEVICE_FLOW === "1") return false;
|
|
@@ -6852,13 +6856,15 @@ async function canOpenBrowser() {
|
|
|
6852
6856
|
return true;
|
|
6853
6857
|
}
|
|
6854
6858
|
async function login(options) {
|
|
6855
|
-
const clientId = await
|
|
6859
|
+
const { clientId, authUrl: workosAuthUrl } = await fetchWorkosLoginConfig(
|
|
6860
|
+
options.siteUrl
|
|
6861
|
+
);
|
|
6856
6862
|
const codeVerifier = crypto.randomBytes(32).toString("base64url");
|
|
6857
6863
|
const codeChallenge = crypto.createHash("sha256").update(codeVerifier).digest("base64url");
|
|
6858
6864
|
const state = crypto.randomBytes(16).toString("hex");
|
|
6859
6865
|
const { port, waitForCode, close } = await startCallbackServer(state);
|
|
6860
6866
|
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
6861
|
-
const authUrl = new URL(`${
|
|
6867
|
+
const authUrl = new URL(`${workosAuthUrl}/user_management/authorize`);
|
|
6862
6868
|
authUrl.searchParams.set("client_id", clientId);
|
|
6863
6869
|
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
6864
6870
|
authUrl.searchParams.set("response_type", "code");
|
|
@@ -6907,7 +6913,8 @@ async function login(options) {
|
|
|
6907
6913
|
email: data.user.email,
|
|
6908
6914
|
name: userName2
|
|
6909
6915
|
},
|
|
6910
|
-
workosClientId: clientId
|
|
6916
|
+
workosClientId: clientId,
|
|
6917
|
+
siteUrl: options.siteUrl
|
|
6911
6918
|
},
|
|
6912
6919
|
options.envName
|
|
6913
6920
|
);
|
|
@@ -6994,7 +7001,7 @@ function startCallbackServer(expectedState) {
|
|
|
6994
7001
|
function sleep(ms) {
|
|
6995
7002
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6996
7003
|
}
|
|
6997
|
-
async function
|
|
7004
|
+
async function fetchWorkosClientId(siteUrl) {
|
|
6998
7005
|
const response = await fetch(`${siteUrl}/api/auth/config`);
|
|
6999
7006
|
const data = await response.json();
|
|
7000
7007
|
if (!response.ok || data.ok === false || !data.workosClientId) {
|
|
@@ -7079,7 +7086,7 @@ async function pollForTokens(clientId, authorization) {
|
|
|
7079
7086
|
throw new Error("Device authorization timed out. Run `fml login` again.");
|
|
7080
7087
|
}
|
|
7081
7088
|
async function deviceLogin(options) {
|
|
7082
|
-
const clientId = await
|
|
7089
|
+
const clientId = await fetchWorkosClientId(options.siteUrl);
|
|
7083
7090
|
const authorization = await requestDeviceAuthorization(clientId);
|
|
7084
7091
|
console.log("");
|
|
7085
7092
|
console.log(" Sign in with this code:");
|
|
@@ -7105,7 +7112,8 @@ async function deviceLogin(options) {
|
|
|
7105
7112
|
email: data.user.email,
|
|
7106
7113
|
name
|
|
7107
7114
|
},
|
|
7108
|
-
workosClientId: clientId
|
|
7115
|
+
workosClientId: clientId,
|
|
7116
|
+
siteUrl: options.siteUrl
|
|
7109
7117
|
},
|
|
7110
7118
|
options.envName
|
|
7111
7119
|
);
|
|
@@ -7146,7 +7154,15 @@ function resolveGitHubToken() {
|
|
|
7146
7154
|
}
|
|
7147
7155
|
|
|
7148
7156
|
// src/commands/login.ts
|
|
7149
|
-
function
|
|
7157
|
+
function prepareLoginEnvironment(backendUrl) {
|
|
7158
|
+
if (backendUrl) {
|
|
7159
|
+
const convexUrl = normalizeConvexUrl(backendUrl);
|
|
7160
|
+
setActiveEnvironment("custom", convexUrl);
|
|
7161
|
+
return {
|
|
7162
|
+
envName: "custom",
|
|
7163
|
+
siteUrl: getSiteUrlForConvexUrl(convexUrl)
|
|
7164
|
+
};
|
|
7165
|
+
}
|
|
7150
7166
|
const environment = getActiveEnv();
|
|
7151
7167
|
return {
|
|
7152
7168
|
envName: environment.name,
|
|
@@ -7285,8 +7301,8 @@ async function selectOrg(environment) {
|
|
|
7285
7301
|
} catch {
|
|
7286
7302
|
}
|
|
7287
7303
|
}
|
|
7288
|
-
async function runServiceTokenLogin(refreshToken) {
|
|
7289
|
-
const environment =
|
|
7304
|
+
async function runServiceTokenLogin(refreshToken, backendUrl) {
|
|
7305
|
+
const environment = prepareLoginEnvironment(backendUrl);
|
|
7290
7306
|
const envName = environment.envName;
|
|
7291
7307
|
if (!isValidEnvName(envName)) {
|
|
7292
7308
|
throw new Error(
|
|
@@ -7308,9 +7324,9 @@ async function runServiceTokenLogin(refreshToken) {
|
|
|
7308
7324
|
"Queries and agent activity sync will use the stored service token."
|
|
7309
7325
|
);
|
|
7310
7326
|
}
|
|
7311
|
-
async function handleServiceTokenLogin(refreshToken) {
|
|
7327
|
+
async function handleServiceTokenLogin(refreshToken, backendUrl) {
|
|
7312
7328
|
try {
|
|
7313
|
-
await runServiceTokenLogin(refreshToken);
|
|
7329
|
+
await runServiceTokenLogin(refreshToken, backendUrl);
|
|
7314
7330
|
process.exit(0);
|
|
7315
7331
|
} catch (err) {
|
|
7316
7332
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -7324,12 +7340,12 @@ async function handleServiceTokenLogin(refreshToken) {
|
|
|
7324
7340
|
}
|
|
7325
7341
|
}
|
|
7326
7342
|
async function runInteractiveLogin(opts = {}) {
|
|
7327
|
-
const environment =
|
|
7343
|
+
const environment = prepareLoginEnvironment(opts.backendUrl);
|
|
7328
7344
|
const envName = environment.envName;
|
|
7329
|
-
const
|
|
7345
|
+
const stored = readTokens(envName);
|
|
7346
|
+
const canReuseStoredLogin = !opts.backendUrl || stored?.siteUrl === environment.siteUrl;
|
|
7347
|
+
const existingToken = canReuseStoredLogin ? await getValidToken({ env: envName }) : null;
|
|
7330
7348
|
if (existingToken) {
|
|
7331
|
-
const { readTokens: readTokens2 } = await import("./token-store-QYXUL4NG.js");
|
|
7332
|
-
const stored = readTokens2(envName);
|
|
7333
7349
|
if (stored?.tokenType === "service") {
|
|
7334
7350
|
const label = stored.user.id === SERVICE_TOKEN_LOGIN_USER_ID ? "a service token" : `${stored.user.name} (${stored.user.email})`;
|
|
7335
7351
|
console.log(`Already logged in with ${label} on ${envName}.`);
|
|
@@ -7356,11 +7372,14 @@ async function runInteractiveLogin(opts = {}) {
|
|
|
7356
7372
|
}
|
|
7357
7373
|
async function handleLogin(opts) {
|
|
7358
7374
|
if (opts?.serviceToken) {
|
|
7359
|
-
await handleServiceTokenLogin();
|
|
7375
|
+
await handleServiceTokenLogin(void 0, opts.backendUrl);
|
|
7360
7376
|
return;
|
|
7361
7377
|
}
|
|
7362
7378
|
try {
|
|
7363
|
-
await runInteractiveLogin({
|
|
7379
|
+
await runInteractiveLogin({
|
|
7380
|
+
device: opts?.device,
|
|
7381
|
+
backendUrl: opts?.backendUrl
|
|
7382
|
+
});
|
|
7364
7383
|
process.exit(0);
|
|
7365
7384
|
} catch (err) {
|
|
7366
7385
|
Sentry.captureException(err);
|
|
@@ -8822,7 +8841,7 @@ async function handleConfigDetail(opts) {
|
|
|
8822
8841
|
// src/commands/tools.ts
|
|
8823
8842
|
import { readFileSync } from "fs";
|
|
8824
8843
|
import path28 from "path";
|
|
8825
|
-
var pluginVersion = true ? "0.8.
|
|
8844
|
+
var pluginVersion = true ? "0.8.6-rc.2+bda7cc0a" : void 0;
|
|
8826
8845
|
async function getApi() {
|
|
8827
8846
|
const api = await getAuthenticatedClient();
|
|
8828
8847
|
if (!api) {
|
|
@@ -8979,7 +8998,7 @@ if (process.argv.length <= 2 || process.argv.includes("--help") || process.argv.
|
|
|
8979
8998
|
printBanner();
|
|
8980
8999
|
}
|
|
8981
9000
|
var program = new Command().name("fml").description("FML CLI and agent tools").version(
|
|
8982
|
-
true ? "0.8.
|
|
9001
|
+
true ? "0.8.6-rc.2+bda7cc0a" : "dev"
|
|
8983
9002
|
);
|
|
8984
9003
|
function formatCommandInventory(cmd, prefix = "") {
|
|
8985
9004
|
const name = prefix ? `${prefix} ${cmd.name()}` : cmd.name();
|
|
@@ -9028,11 +9047,14 @@ program.command("update").description("Update fml when a newer release is availa
|
|
|
9028
9047
|
).action(
|
|
9029
9048
|
(opts) => handleUpdate({ nonInteractive: Boolean(opts.nonInteractive) })
|
|
9030
9049
|
);
|
|
9031
|
-
program.command("login").description("Sign in to your FML account").
|
|
9050
|
+
program.command("login").description("Sign in to your FML account").argument(
|
|
9051
|
+
"[backend-url]",
|
|
9052
|
+
"Self-hosted FML backend URL (saved as the active custom environment)"
|
|
9053
|
+
).option("--device", "Use device authorization flow (no browser needed)").option(
|
|
9032
9054
|
"--service-token",
|
|
9033
9055
|
"Sign in with an org service refresh token (prompts for fml_srt_*)"
|
|
9034
9056
|
).action(
|
|
9035
|
-
(opts) => handleLogin(opts)
|
|
9057
|
+
(backendUrl, opts) => handleLogin({ ...opts, backendUrl })
|
|
9036
9058
|
);
|
|
9037
9059
|
program.command("logout").description("Sign out and clear stored credentials").action(() => handleLogout());
|
|
9038
9060
|
program.command("org").description("Show or select organization").argument("[slug]", "Org slug to select").action((slug) => handleOrg(slug));
|
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-FGR7SHV7.js";
|
|
5
5
|
import {
|
|
6
6
|
getActiveHookDestinationBinding
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-GST2GTOC.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-3T5UCGBR.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-KWCFT54L.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-RZ5LWWRO.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-KWCFT54L.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-GQ2WVOGY.js";
|
|
15
15
|
import {
|
|
16
16
|
createHookSyncLoop,
|
|
17
17
|
getActiveHookDestinationBinding
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-GST2GTOC.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-3T5UCGBR.js";
|
|
34
34
|
import "./chunk-7V7G7NVF.js";
|
|
35
35
|
import {
|
|
36
36
|
ObserverSyncCycleAbortedError,
|
|
37
37
|
runObserverSyncCycleSubprocess
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-JEZPS7F5.js";
|
|
39
39
|
import {
|
|
40
40
|
createCliRawSync
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-Z2LWDZ6Z.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-KWCFT54L.js";
|
|
60
60
|
import "./chunk-MLKGABMK.js";
|
|
61
61
|
|
|
62
62
|
// src/observer-server.ts
|
|
@@ -1200,14 +1200,17 @@ function createObserverSyncLoop(opts) {
|
|
|
1200
1200
|
}
|
|
1201
1201
|
|
|
1202
1202
|
// src/observer/auto-update.ts
|
|
1203
|
-
var AUTO_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
1203
|
+
var AUTO_UPDATE_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
1204
1204
|
var AUTO_UPDATE_JITTER_MS = 10 * 60 * 1e3;
|
|
1205
|
+
var AUTO_UPDATE_SESSION_START_COOLDOWN_MS = 60 * 60 * 1e3;
|
|
1205
1206
|
function errorMessage2(error) {
|
|
1206
1207
|
return error instanceof Error ? error.message : String(error);
|
|
1207
1208
|
}
|
|
1208
1209
|
function createAutoUpdater(dependencies) {
|
|
1209
1210
|
let timer;
|
|
1210
1211
|
let stopped = true;
|
|
1212
|
+
let checkInFlight = false;
|
|
1213
|
+
let lastSessionStartCheckAtMs;
|
|
1211
1214
|
let generation = 0;
|
|
1212
1215
|
const nextDelay = () => {
|
|
1213
1216
|
if (dependencies.jitterMs <= 0) return dependencies.intervalMs;
|
|
@@ -1220,18 +1223,35 @@ function createAutoUpdater(dependencies) {
|
|
|
1220
1223
|
timer = setTimeout(onTick, nextDelay());
|
|
1221
1224
|
timer.unref();
|
|
1222
1225
|
};
|
|
1223
|
-
const
|
|
1224
|
-
const tickGeneration = generation;
|
|
1225
|
-
timer = void 0;
|
|
1226
|
+
const runUpdateCheck = async (checkGeneration) => {
|
|
1226
1227
|
try {
|
|
1227
1228
|
const result = await dependencies.runCheck();
|
|
1228
|
-
if (!stopped && result.newer)
|
|
1229
|
+
if (!stopped && checkGeneration === generation && result.newer) {
|
|
1230
|
+
dependencies.spawnUpdate();
|
|
1231
|
+
}
|
|
1229
1232
|
} catch (error) {
|
|
1230
|
-
if (!stopped) {
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1233
|
+
if (!stopped && checkGeneration === generation) {
|
|
1234
|
+
try {
|
|
1235
|
+
dependencies.log(
|
|
1236
|
+
`[fml] Auto-update check failed: ${errorMessage2(error)}`
|
|
1237
|
+
);
|
|
1238
|
+
} catch {
|
|
1239
|
+
}
|
|
1234
1240
|
}
|
|
1241
|
+
} finally {
|
|
1242
|
+
checkInFlight = false;
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
const startUpdateCheck = (checkGeneration) => {
|
|
1246
|
+
if (stopped || checkInFlight) return null;
|
|
1247
|
+
checkInFlight = true;
|
|
1248
|
+
return runUpdateCheck(checkGeneration);
|
|
1249
|
+
};
|
|
1250
|
+
const onTick = async () => {
|
|
1251
|
+
const tickGeneration = generation;
|
|
1252
|
+
timer = void 0;
|
|
1253
|
+
try {
|
|
1254
|
+
await startUpdateCheck(tickGeneration);
|
|
1235
1255
|
} finally {
|
|
1236
1256
|
if (tickGeneration === generation) schedule();
|
|
1237
1257
|
}
|
|
@@ -1244,6 +1264,17 @@ function createAutoUpdater(dependencies) {
|
|
|
1244
1264
|
stopped = false;
|
|
1245
1265
|
schedule();
|
|
1246
1266
|
},
|
|
1267
|
+
onSessionStart() {
|
|
1268
|
+
if (stopped) return;
|
|
1269
|
+
const now = dependencies.nowMs();
|
|
1270
|
+
if (lastSessionStartCheckAtMs !== void 0 && now - lastSessionStartCheckAtMs < dependencies.sessionStartCooldownMs) {
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1273
|
+
const check = startUpdateCheck(generation);
|
|
1274
|
+
if (!check) return;
|
|
1275
|
+
lastSessionStartCheckAtMs = now;
|
|
1276
|
+
void check;
|
|
1277
|
+
},
|
|
1247
1278
|
stop() {
|
|
1248
1279
|
stopped = true;
|
|
1249
1280
|
generation += 1;
|
|
@@ -1449,7 +1480,7 @@ var hookRejectionStatus = () => ({
|
|
|
1449
1480
|
...lastRejectedReason !== void 0 ? { lastRejectedReason } : {},
|
|
1450
1481
|
...lastRejectedTarget !== void 0 ? { lastRejectedTarget } : {}
|
|
1451
1482
|
});
|
|
1452
|
-
var packageVersion = true ? "0.8.
|
|
1483
|
+
var packageVersion = true ? "0.8.6-rc.2+bda7cc0a" : "dev";
|
|
1453
1484
|
var health = () => ({
|
|
1454
1485
|
status: "ok",
|
|
1455
1486
|
service: OBSERVER_SERVICE_NAME,
|
|
@@ -1626,8 +1657,9 @@ var captureHookRequest = (request, metadata) => {
|
|
|
1626
1657
|
} catch {
|
|
1627
1658
|
}
|
|
1628
1659
|
}
|
|
1660
|
+
let captured;
|
|
1629
1661
|
try {
|
|
1630
|
-
database.captureHookEvent({
|
|
1662
|
+
captured = database.captureHookEvent({
|
|
1631
1663
|
...event,
|
|
1632
1664
|
...destination ? { destination } : {}
|
|
1633
1665
|
});
|
|
@@ -1639,6 +1671,9 @@ var captureHookRequest = (request, metadata) => {
|
|
|
1639
1671
|
);
|
|
1640
1672
|
return terminal ? "terminal_rejected" : "retry";
|
|
1641
1673
|
}
|
|
1674
|
+
if (captured && event.eventType === "SessionStart") {
|
|
1675
|
+
autoUpdater?.onSessionStart();
|
|
1676
|
+
}
|
|
1642
1677
|
hookSyncLoop?.wake();
|
|
1643
1678
|
return "committed";
|
|
1644
1679
|
};
|
|
@@ -1732,6 +1767,7 @@ try {
|
|
|
1732
1767
|
}),
|
|
1733
1768
|
spawnUpdate: spawnObserverUpdate,
|
|
1734
1769
|
intervalMs: AUTO_UPDATE_INTERVAL_MS,
|
|
1770
|
+
sessionStartCooldownMs: AUTO_UPDATE_SESSION_START_COOLDOWN_MS,
|
|
1735
1771
|
jitterMs: AUTO_UPDATE_JITTER_MS,
|
|
1736
1772
|
log: console.warn
|
|
1737
1773
|
});
|
package/dist/pi/extension.js
CHANGED
|
@@ -1045,7 +1045,7 @@ function parseStoredAuthShape(parsed) {
|
|
|
1045
1045
|
}
|
|
1046
1046
|
const auth = parsed;
|
|
1047
1047
|
const user = auth.user;
|
|
1048
|
-
if (typeof auth.accessToken !== "string" || typeof auth.refreshToken !== "string" || typeof auth.expiresAt !== "number" || !Number.isFinite(auth.expiresAt) || !user || typeof user.id !== "string" || typeof user.email !== "string" || typeof user.name !== "string" || auth.orgId !== void 0 && typeof auth.orgId !== "string" || auth.orgSlug !== void 0 && typeof auth.orgSlug !== "string" || auth.workosClientId !== void 0 && typeof auth.workosClientId !== "string" || auth.tokenType !== void 0 && auth.tokenType !== "oauth" && auth.tokenType !== "service" || auth.refreshInvalidAt !== void 0 && (typeof auth.refreshInvalidAt !== "number" || !Number.isFinite(auth.refreshInvalidAt))) {
|
|
1048
|
+
if (typeof auth.accessToken !== "string" || typeof auth.refreshToken !== "string" || typeof auth.expiresAt !== "number" || !Number.isFinite(auth.expiresAt) || !user || typeof user.id !== "string" || typeof user.email !== "string" || typeof user.name !== "string" || auth.orgId !== void 0 && typeof auth.orgId !== "string" || auth.orgSlug !== void 0 && typeof auth.orgSlug !== "string" || auth.workosClientId !== void 0 && typeof auth.workosClientId !== "string" || auth.siteUrl !== void 0 && typeof auth.siteUrl !== "string" || auth.tokenType !== void 0 && auth.tokenType !== "oauth" && auth.tokenType !== "service" || auth.refreshInvalidAt !== void 0 && (typeof auth.refreshInvalidAt !== "number" || !Number.isFinite(auth.refreshInvalidAt))) {
|
|
1049
1049
|
return null;
|
|
1050
1050
|
}
|
|
1051
1051
|
return auth;
|
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-JEZPS7F5.js";
|
|
5
|
+
import "./chunk-Z2LWDZ6Z.js";
|
|
6
|
+
import "./chunk-KWCFT54L.js";
|
|
7
7
|
import "./chunk-MLKGABMK.js";
|
|
8
8
|
|
|
9
9
|
// src/sync-cycle.ts
|