@frontmcp/adapters 1.11.0-rc.2 → 1.11.1-rc.1

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.
Files changed (35) hide show
  1. package/esm/index.mjs +2 -2
  2. package/esm/openapi/index.mjs +2 -2
  3. package/esm/package.json +6 -6
  4. package/esm/skills/index.mjs +1 -1
  5. package/index.js +2 -2
  6. package/openapi/index.js +2 -2
  7. package/openapi/openapi.adapter.d.ts.map +1 -1
  8. package/openapi/openapi.output-schema.d.ts +11 -0
  9. package/openapi/openapi.output-schema.d.ts.map +1 -0
  10. package/openapi/openapi.utils.d.ts.map +1 -1
  11. package/package.json +6 -6
  12. package/skills/bundle/bundle-diff.d.ts.map +1 -1
  13. package/skills/bundle/bundle.schema.d.ts +1 -0
  14. package/skills/bundle/bundle.schema.d.ts.map +1 -1
  15. package/skills/bundle/bundle.types.d.ts +2 -0
  16. package/skills/bundle/bundle.types.d.ts.map +1 -1
  17. package/skills/bundle/overlay-parser.d.ts.map +1 -1
  18. package/skills/index.d.ts +3 -3
  19. package/skills/index.d.ts.map +1 -1
  20. package/skills/index.js +1 -1
  21. package/skills/openapi/compile-skilled-bundle.d.ts +1 -0
  22. package/skills/openapi/compile-skilled-bundle.d.ts.map +1 -1
  23. package/skills/security/jwt-verifier.d.ts +1 -1
  24. package/skills/security/jwt-verifier.d.ts.map +1 -1
  25. package/skills/security/webhook-replay-guard.d.ts +3 -0
  26. package/skills/security/webhook-replay-guard.d.ts.map +1 -1
  27. package/skills/source-options.d.ts.map +1 -1
  28. package/skills/sources/index.d.ts +3 -3
  29. package/skills/sources/index.d.ts.map +1 -1
  30. package/skills/sources/saas-pull.source.d.ts +50 -12
  31. package/skills/sources/saas-pull.source.d.ts.map +1 -1
  32. package/skills/sources/skill-bundle-source.interface.d.ts +21 -4
  33. package/skills/sources/skill-bundle-source.interface.d.ts.map +1 -1
  34. package/skills/sources/static.source.d.ts +6 -2
  35. package/skills/sources/static.source.d.ts.map +1 -1
@@ -1,7 +1,7 @@
1
1
  import type { FrontMcpLogger } from '@frontmcp/sdk';
2
2
  import type { ResolvedBundle } from '../bundle/bundle.types';
3
3
  import type { SaasSourceOptions } from '../source-options';
4
- import type { BundleSourceDeps, BundleSourceListener, SkillBundleSource } from './skill-bundle-source.interface';
4
+ import type { BundlePushReceiver, BundleSourceDeps, BundleSourceListener, SkillBundleSource } from './skill-bundle-source.interface';
5
5
  /**
6
6
  * The pinned pull token failed verification against `jwksUrl`, `expectedIssuer`
7
7
  * or `expectedAudience`. Unlike an outage, this never falls back to a cached
@@ -10,6 +10,14 @@ import type { BundleSourceDeps, BundleSourceListener, SkillBundleSource } from '
10
10
  export declare class SaasPullTokenRejectedError extends Error {
11
11
  constructor(reason: string);
12
12
  }
13
+ /**
14
+ * The token of a pushed bundle was refused: it fails the checks the pull token passes (`invalid-token`), or a push
15
+ * already used it (`replayed`). The pushed bundle is not applied.
16
+ */
17
+ export declare class SaasPushRefusedError extends Error {
18
+ readonly refusal: 'invalid-token' | 'replayed';
19
+ constructor(refusal: 'invalid-token' | 'replayed', reason: string);
20
+ }
13
21
  /**
14
22
  * Pulls bundles from a configured SaaS endpoint via authenticated HTTPS.
15
23
  *
@@ -17,13 +25,16 @@ export declare class SaasPullTokenRejectedError extends Error {
17
25
  * - Always attempts a fresh pull on `start()`.
18
26
  * - If the pull fails AND a cached bundle exists on disk, falls back to it
19
27
  * and emits a warning. This prevents a SaaS outage at boot from killing
20
- * the customer's MCP server.
21
- * - If both pull and cache fail, `start()` throws.
28
+ * the customer's MCP server. The cache holds the last bundle the plugin
29
+ * applied ({@link SaasPullSource.keepBundle}): a pulled bundle that fails
30
+ * its signature or apply never replaces it.
31
+ * - If both pull and cache fail, `start()` throws. Polling still starts, so a
32
+ * later pull that succeeds loads the bundle.
22
33
  *
23
34
  * Refresh: poll on `pollIntervalMs`. Single-flight per source — overlapping
24
- * polls are skipped, never queued. Webhook support is gated behind
25
- * `enableWebhook` and deferred to v1.2.x (route mounting requires plugin HTTP
26
- * infrastructure not yet in scope).
35
+ * polls are skipped, never queued. With `enableWebhook` the source also takes
36
+ * pushed bundles ({@link SaasPullSource.verifyPushToken}): the plugin serves
37
+ * them at `POST /__skilled_openapi/push`.
27
38
  *
28
39
  * Before every pull the pinned `authToken` is verified: it must be a JWT signed
29
40
  * by a key in the issuer's JWKS (`jwksUrl`), with `iss` equal to
@@ -36,7 +47,7 @@ export declare class SaasPullTokenRejectedError extends Error {
36
47
  * NOTE: Bundle signature verification is applied by the bundle-sync service
37
48
  * before the bundle becomes active.
38
49
  */
39
- export declare class SaasPullSource implements SkillBundleSource {
50
+ export declare class SaasPullSource implements SkillBundleSource, BundlePushReceiver {
40
51
  private readonly options;
41
52
  private readonly cacheDir;
42
53
  private readonly logger;
@@ -44,20 +55,39 @@ export declare class SaasPullSource implements SkillBundleSource {
44
55
  readonly id: string;
45
56
  private listeners;
46
57
  private pollHandle;
47
- private inFlight;
58
+ /** The pull running now, from start, a poll or a refresh; only one runs at a time. */
59
+ private inFlightPull;
48
60
  private stopped;
49
61
  private readonly jwksService;
62
+ private readonly replayGuard?;
63
+ private pushSigningKeys?;
64
+ private pushSigningKeysLoading?;
50
65
  constructor(options: SaasSourceOptions, cacheDir: string | undefined, logger: FrontMcpLogger, deps?: BundleSourceDeps);
66
+ /** This source, when `enableWebhook` is on: it then takes bundles pushed to the server. */
67
+ get push(): BundlePushReceiver | undefined;
68
+ /**
69
+ * Check the token of a pushed bundle: by the rules the pull token passes (a key in `jwksUrl`, `iss`, `aud`,
70
+ * `resource`, expiry), then by the replay guard, so its `iat` must be within five minutes and its `jti` unused.
71
+ * Throws {@link SaasPushRefusedError}, or a plain Error when the JWKS can't be read.
72
+ */
73
+ verifyPushToken(token: string): Promise<void>;
74
+ /** Keep a bundle the plugin applied, pulled or pushed, as the last good one a start falls back to. */
75
+ keepBundle(bundle: ResolvedBundle): Promise<void>;
51
76
  start(): Promise<void>;
77
+ private pullAtStart;
78
+ /** Run `pull` as the one pull in flight, so a start, a poll and a refresh never pull at once. */
79
+ private exclusivePull;
52
80
  onChange(listener: BundleSourceListener): () => void;
53
81
  stop(): Promise<void>;
54
82
  private schedulePoll;
55
83
  /**
56
- * Manually pull a fresh bundle, persist it, and notify listeners. Drive this
84
+ * Manually pull a fresh bundle and notify listeners, resolving once they are
85
+ * done with it (the plugin applied and kept it, or refused it). Drive this
57
86
  * from a Cron Trigger / Durable Object alarm on runtimes without background
58
- * timers (where `disablePolling` is set). Single-flight: returns `undefined`
59
- * if a pull is already in flight; throws if the pull itself fails (the caller
60
- * — e.g. a scheduled handler — decides how to surface it).
87
+ * timers (where `disablePolling` is set). Single-flight: while a pull is
88
+ * already in flight it waits for that pull to finish, applied and kept, and
89
+ * returns `undefined` without pulling again; throws if its own pull fails (the
90
+ * caller — e.g. a scheduled handler — decides how to surface it).
61
91
  */
62
92
  refresh(): Promise<ResolvedBundle | undefined>;
63
93
  private pollOnce;
@@ -71,6 +101,14 @@ export declare class SaasPullSource implements SkillBundleSource {
71
101
  * plain Error when the JWKS can't be fetched (an outage).
72
102
  */
73
103
  private verifyPullToken;
104
+ /**
105
+ * The issuer's signing keys for checking a push token: fetched at most once a minute, and shared by concurrent
106
+ * pushes. A pull always fetches them, so a key the issuer removed stops a pull at once.
107
+ */
108
+ private signingKeysForPush;
109
+ private fetchSigningKeys;
110
+ /** Check a token the issuer signed, against its JWKS, issuer and audience. */
111
+ private verifyIssuedToken;
74
112
  private fetchOnce;
75
113
  /** Where the last-good bundle is kept, for messages: an injected store (a Worker's KV) has no file path. */
76
114
  private cacheLocation;
@@ -1 +1 @@
1
- {"version":3,"file":"saas-pull.source.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/saas-pull.source.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAMjH;;;;GAIG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,MAAM,EAAE,MAAM;CAI3B;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,cAAe,YAAW,iBAAiB;IAUpD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAZvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuB;gBAGhC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE,gBAAqB;IAKxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC5B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAO9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,OAAO,CAAC,YAAY;IAcpB;;;;;;OAMG;IACG,OAAO,IAAI,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;YAatC,QAAQ;cAyBN,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBhH;;;;OAIG;YACW,eAAe;YA2Cf,SAAS;IAkBvB,4GAA4G;IAC5G,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,SAAS;YAKH,YAAY;YAeZ,SAAS;IAkBvB,OAAO,CAAC,MAAM;CASf"}
1
+ {"version":3,"file":"saas-pull.source.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/saas-pull.source.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,iCAAiC,CAAC;AASzC;;;;GAIG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,MAAM,EAAE,MAAM;CAI3B;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,UAAU;gBAArC,OAAO,EAAE,eAAe,GAAG,UAAU,EAC9C,MAAM,EAAE,MAAM;CAKjB;AAqCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,cAAe,YAAW,iBAAiB,EAAE,kBAAkB;IAcxE,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAhBvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,UAAU,CAA6B;IAC/C,sFAAsF;IACtF,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuB;IACnD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAqB;IAClD,OAAO,CAAC,eAAe,CAAC,CAAyC;IACjE,OAAO,CAAC,sBAAsB,CAAC,CAAqB;gBAGjC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE,gBAAqB;IAM9C,2FAA2F;IAC3F,IAAI,IAAI,IAAI,kBAAkB,GAAG,SAAS,CAEzC;IAED;;;;OAIG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBnD,sGAAsG;IACtG,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAcd,WAAW;IAsBzB,iGAAiG;IACjG,OAAO,CAAC,aAAa;IAQrB,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAO9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,OAAO,CAAC,YAAY;IAcpB;;;;;;;;OAQG;IACG,OAAO,IAAI,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;YAatC,QAAQ;cAwBN,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBhH;;;;OAIG;YACW,eAAe;IAK7B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;YAcZ,gBAAgB;IA0B9B,8EAA8E;YAChE,iBAAiB;YAuBjB,SAAS;IAkBvB,4GAA4G;IAC5G,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,SAAS;YAKH,YAAY;YAeZ,SAAS;YAkBT,MAAM;CASrB"}
@@ -8,12 +8,15 @@ import type { ResolvedBundle } from '../bundle/bundle.types';
8
8
  * its initial fetch and begins any background polling/watching.
9
9
  * - `onChange()` registers a listener invoked every time a new bundle is
10
10
  * available (initial fetch + every refresh).
11
+ * - `keepBundle()`, on a source with a last-good cache, keeps a bundle once
12
+ * the plugin has applied it.
11
13
  * - `stop()` halts all background work and releases resources.
12
14
  *
13
15
  * Sources are responsible for parsing/validating their input into a
14
16
  * ResolvedBundle (typically by calling `parseOverlay` from bundle/overlay-parser).
15
17
  * They MUST NOT verify signatures themselves — the bundle-sync service applies
16
- * the signature gate before swapping the bundle into the registry.
18
+ * the signature gate before swapping the bundle into the registry. For the same
19
+ * reason they never cache a bundle they fetched until they are asked to keep it.
17
20
  */
18
21
  export interface SkillBundleSource {
19
22
  /** Stable id of this source (e.g. 'static:/path/to/bundle.yaml'). */
@@ -35,14 +38,28 @@ export interface SkillBundleSource {
35
38
  * remote/pulling sources implement it. On runtimes with no background
36
39
  * execution (Cloudflare Workers) a Cron Trigger / Durable Object alarm
37
40
  * calls this instead of relying on an internal timer. Resolves to the new
38
- * bundle, or `undefined` if a pull is already in flight / the source is
39
- * stopped.
41
+ * bundle once its listeners are done with it (the plugin has applied it, or
42
+ * refused it), or to `undefined` if a pull is already in flight / the source
43
+ * is stopped.
40
44
  */
41
45
  refresh?(): Promise<ResolvedBundle | undefined>;
46
+ /**
47
+ * Keep a bundle the plugin applied as the last good one, which a start that can't fetch falls back to. Present on
48
+ * a source with a last-good cache: the `saas` source.
49
+ */
50
+ keepBundle?(bundle: ResolvedBundle): Promise<void>;
51
+ /** Present on a source that takes pushed bundles: the `saas` source with `enableWebhook`. */
52
+ readonly push?: BundlePushReceiver;
42
53
  /** Halt background work; idempotent. */
43
54
  stop(): Promise<void>;
44
55
  }
45
- export type BundleSourceListener = (bundle: ResolvedBundle) => void;
56
+ /** The check a pushed bundle's token passes before the bundle is applied. */
57
+ export interface BundlePushReceiver {
58
+ /** Resolves when the push token is accepted; throws when it is refused or can't be checked. */
59
+ verifyPushToken(token: string): Promise<void>;
60
+ }
61
+ /** Takes each new bundle; a pulling source waits for a promise it returns before its pull counts as done. */
62
+ export type BundleSourceListener = (bundle: ResolvedBundle) => unknown;
46
63
  /**
47
64
  * Pluggable last-good bundle cache. The default (Node) implementation writes to
48
65
  * disk; V8-isolate runtimes (Cloudflare Workers) inject a KV-backed store
@@ -1 +1 @@
1
- {"version":3,"file":"skill-bundle-source.interface.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/skill-bundle-source.interface.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI,CAAC;IAErD;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;IAEhD,wCAAwC;IACxC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;AAEpE;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,IAAI,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;IAC5C,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B"}
1
+ {"version":3,"file":"skill-bundle-source.interface.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/skill-bundle-source.interface.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI,CAAC;IAErD;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;IAEhD;;;OAGG;IACH,UAAU,CAAC,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD,6FAA6F;IAC7F,QAAQ,CAAC,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAEnC,wCAAwC;IACxC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,6EAA6E;AAC7E,MAAM,WAAW,kBAAkB;IACjC,+FAA+F;IAC/F,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,6GAA6G;AAC7G,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC;AAEvE;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,IAAI,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;IAC5C,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B"}
@@ -3,7 +3,9 @@ import type { StaticSourceOptions } from '../source-options';
3
3
  import type { BundleSourceListener, SkillBundleSource } from './skill-bundle-source.interface';
4
4
  /**
5
5
  * Loads a bundle from a local file (YAML or JSON). Optionally watches the
6
- * file for changes via `fs.watch` and re-fetches on edit.
6
+ * file for changes via `fs.watch` and re-fetches on edit. The watch starts
7
+ * before the first read, so fixing a file that failed to load reloads it. A
8
+ * refresh that reads the same content as the last read applies nothing.
7
9
  *
8
10
  * Bundle file extensions:
9
11
  * - `.yaml` / `.yml` — parsed as YAML
@@ -18,11 +20,13 @@ export declare class StaticSource implements SkillBundleSource {
18
20
  private watcher;
19
21
  private debounceTimer;
20
22
  private stopped;
23
+ private lastContent;
21
24
  constructor(options: StaticSourceOptions, logger: FrontMcpLogger);
22
25
  start(): Promise<void>;
23
26
  onChange(listener: BundleSourceListener): () => void;
24
27
  stop(): Promise<void>;
25
- private fetchOnce;
28
+ private readBundleFile;
29
+ private parse;
26
30
  private notify;
27
31
  private beginWatch;
28
32
  private scheduleRefresh;
@@ -1 +1 @@
1
- {"version":3,"file":"static.source.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/static.source.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE/F;;;;;;;;GAQG;AACH,qBAAa,YAAa,YAAW,iBAAiB;IASlD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IATzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,OAAO,CAAS;gBAGL,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,cAAc;IAKnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAO9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAab,SAAS;IAoBvB,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,eAAe;CAaxB"}
1
+ {"version":3,"file":"static.source.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/static.source.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE/F;;;;;;;;;;GAUG;AACH,qBAAa,YAAa,YAAW,iBAAiB;IAUlD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAqB;gBAGrB,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,cAAc;IAKnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAO9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,KAAK;IAkBb,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,eAAe;CAexB"}