@flareum/mcp 0.2.9 → 0.2.11

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.
@@ -8,11 +8,12 @@ export type Probe = (path: string) => boolean;
8
8
  */
9
9
  export declare const chooseStylesDir: (exists: Probe, configured?: string) => string;
10
10
  export declare const autoPullEnabled: (env: Record<string, string | undefined>) => boolean;
11
- /** Only ever the FIRST time: an existing directory is the developer's, and `flareum pull` owns updates. */
12
- export declare const needsFirstPull: (exists: Probe, dir: string) => boolean;
11
+ export declare const STAMP = ".flareum-version";
12
+ export declare const pulledVersion: (read: (path: string) => string | null, dir: string) => string | null;
13
+ export declare const needsPull: (exists: Probe, read: (path: string) => string | null, dir: string, published: string | null) => boolean;
13
14
  export type FirstPull = {
14
15
  ran: false;
15
- reason: 'disabled' | 'already-pulled';
16
+ reason: 'disabled' | 'up-to-date';
16
17
  dir: string;
17
18
  } | {
18
19
  ran: true;
@@ -28,4 +29,4 @@ export declare const firstPullReport: (outcome: FirstPull) => string | null;
28
29
  /** Writes under `root`, refusing nothing the pull already refuses (see isWritablePath). */
29
30
  export declare const fileWriter: (root: string) => (path: string, contents: string) => Promise<void>;
30
31
  export declare const configuredOut: (cwd: string, env: Record<string, string | undefined>) => string | undefined;
31
- export declare const runFirstPull: (client: Pick<FlareumClient, "files" | "file">, cwd: string, env: Record<string, string | undefined>, configuredOut?: string) => Promise<FirstPull>;
32
+ export declare const runFirstPull: (client: Pick<FlareumClient, "files" | "file" | "published">, cwd: string, env: Record<string, string | undefined>, configuredOut?: string) => Promise<FirstPull>;
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
2
2
  import { mkdir, writeFile } from 'node:fs/promises';
3
3
  import { dirname, join, resolve } from 'node:path';
4
4
  import { CONFIG_PATH } from './config.js';
5
- import { pullStyles } from './pull.js';
5
+ import { isRetryable, pullStyles } from './pull.js';
6
6
  // Most specific first. A repo that keeps stylesheets in app/styles gets them there rather than in a
7
7
  // src/styles nobody in that project looks at.
8
8
  const STYLE_ROOTS = [
@@ -29,8 +29,18 @@ export const chooseStylesDir = (exists, configured) => {
29
29
  // Opt-out, not opt-in: a project with no stylesheets is the case this exists for, and a stdio server
30
30
  // has nobody to ask at startup. Anything but an explicit off means on.
31
31
  export const autoPullEnabled = (env) => !['off', 'false', '0', 'no'].includes((env.FLAREUM_AUTO_PULL ?? '').trim().toLowerCase());
32
- /** Only ever the FIRST time: an existing directory is the developer's, and `flareum pull` owns updates. */
33
- export const needsFirstPull = (exists, dir) => !exists(dir);
32
+ // A stamp beside the files, not in config.json: config is the developer's, this is bookkeeping.
33
+ export const STAMP = '.flareum-version';
34
+ export const pulledVersion = (read, dir) => read(join(dir, STAMP))?.trim() || null;
35
+ // Pull when there is nothing here, or when what is published is not what is on disk. Connecting
36
+ // used to be a one-time event, so a project pulled once never saw another push.
37
+ export const needsPull = (exists, read, dir, published) => {
38
+ if (!exists(dir))
39
+ return true;
40
+ if (!published)
41
+ return false;
42
+ return pulledVersion(read, dir) !== published;
43
+ };
34
44
  export const firstPullReport = (outcome) => {
35
45
  // Silence is right for a start that did nothing — this prints on every server start.
36
46
  if (!outcome.ran && outcome.reason !== 'failed')
@@ -68,13 +78,27 @@ export const configuredOut = (cwd, env) => {
68
78
  };
69
79
  export const runFirstPull = async (client, cwd, env, configuredOut) => {
70
80
  const exists = path => existsSync(resolve(cwd, path));
81
+ const read = (path) => {
82
+ try {
83
+ return readFileSync(resolve(cwd, path), 'utf8');
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ };
71
89
  const dir = chooseStylesDir(exists, configuredOut);
72
90
  if (!autoPullEnabled(env))
73
91
  return { ran: false, reason: 'disabled', dir };
74
- if (!needsFirstPull(exists, dir))
75
- return { ran: false, reason: 'already-pulled', dir };
76
92
  try {
77
- return { ran: true, dir, result: await pullStyles(client, fileWriter(resolve(cwd, dir))) };
93
+ const published = await client.published().then(r => r.publishedVersionId).catch(() => null);
94
+ if (!needsPull(exists, read, dir, published))
95
+ return { ran: false, reason: 'up-to-date', dir };
96
+ const result = await pullStyles(client, fileWriter(resolve(cwd, dir)));
97
+ // Stamped only when the WHOLE version landed. pullStyles resolves even when files failed, so
98
+ // stamping on its return recorded a half-pulled folder as complete and never retried it.
99
+ if (!isRetryable(result))
100
+ await writeFile(resolve(cwd, dir, STAMP), `${result.publishedVersionId}\n`, 'utf8');
101
+ return { ran: true, dir, result };
78
102
  }
79
103
  catch (error) {
80
104
  // A project with nothing published, an expired key, no network — none of them may stop the server.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flareum/mcp",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Connect a coding agent to a Flareum project's design tokens.",
5
5
  "license": "MIT",
6
6
  "author": "Flareum",