@wilm-ai/wilma-cli 2.1.0 → 2.1.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.
package/README.md CHANGED
@@ -72,7 +72,7 @@ wilma find-school <city or school>
72
72
 
73
73
  ## Other
74
74
  ```bash
75
- wilma update # commands say on stderr when a newer version is out (checked once a day; WILMAI_NO_UPDATE_CHECK=1 turns it off)
75
+ wilma update # when a newer version is out, a command says so on stderr, at most once a day (WILMAI_NO_UPDATE_CHECK=1 turns it off)
76
76
  wilma config clear # deletes every saved login and session
77
77
  wilma --version
78
78
  ```
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import { ENV_VARS, isMfaFailure, mfaCallbackFor, resolveAccounts, saveLogin, ver
17
17
  import { createUniqueDownloadFile } from "./downloads.js";
18
18
  import { openBrowser, startLoginServer } from "./login-server.js";
19
19
  import { runMcpServer } from "./mcp.js";
20
- import { cliUpdateNotice, isNewerVersion, latestWithin, startUpdateCheck, updateChecksEnabled } from "./update-check.js";
20
+ import { claimNotice, cliUpdateNotice, isNewerVersion, latestWithin, startUpdateCheck, updateChecksEnabled } from "./update-check.js";
21
21
  import { toAgentJson } from "./output-json.js";
22
22
  import { clearSessions, fileSessionStore } from "./session-store.js";
23
23
  import { normalizeTenantUrl, resolveTenant, searchTenants } from "./tenant-search.js";
@@ -757,7 +757,7 @@ async function showUpdateNotice(check) {
757
757
  if (!latestVersion)
758
758
  return;
759
759
  const currentVersion = await readPackageVersion();
760
- if (isNewerVersion(latestVersion, currentVersion)) {
760
+ if (isNewerVersion(latestVersion, currentVersion) && (await claimNotice(latestVersion))) {
761
761
  process.stderr.write(`\n${cliUpdateNotice(currentVersion, latestVersion)}\n`);
762
762
  }
763
763
  }
@@ -8,6 +8,8 @@ export declare function installKind(env?: NodeJS.ProcessEnv, scriptPath?: string
8
8
  export declare function updateChecksEnabled(env?: NodeJS.ProcessEnv): boolean;
9
9
  export declare function isNewerVersion(latest: string, current: string): boolean;
10
10
  /** The CLI's notice, for a person or an agent reading stderr. */
11
+ /** Release notes: a wilm.ai redirect, so the target can move without a CLI release. */
12
+ export declare const CHANGES_URL = "https://wilm.ai/changes";
11
13
  export declare function cliUpdateNotice(current: string, latest: string): string;
12
14
  /** The note the MCP server adds for the assistant, who passes it on. */
13
15
  export declare function mcpUpdateNote(kind: InstallKind, current: string, latest: string): string;
@@ -23,5 +25,11 @@ export interface UpdateCheck {
23
25
  * a timeout on every command.
24
26
  */
25
27
  export declare function startUpdateCheck(): UpdateCheck;
28
+ /**
29
+ * Whether to show the CLI's notice for `latest` now, and if so, record it: at
30
+ * most once a day, and right away for a version not announced before. An
31
+ * agent's morning run of ten commands should see it once, not ten times.
32
+ */
33
+ export declare function claimNotice(latest: string, now?: number): Promise<boolean>;
26
34
  /** The latest version if the check has an answer within `waitMs`, else null. */
27
35
  export declare function latestWithin(check: UpdateCheck, waitMs: number): Promise<string | null>;
@@ -3,10 +3,10 @@ import { dirname, resolve, sep } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { getConfigPath } from "./config.js";
5
5
  /*
6
- * "A newer WilmAI is available." The CLI prints it on stderr (people in a
7
- * terminal and agents like OpenClaw both read it there); the MCP server adds it
8
- * once to a tool result so the assistant can tell the user. How to update
9
- * depends on how WilmAI was installed.
6
+ * "A newer WilmAI is available." The CLI prints it on stderr at most once a day
7
+ * (people in a terminal and agents like OpenClaw both read it there); the MCP
8
+ * server adds it once to a tool result so the assistant can tell the user. How
9
+ * to update depends on how WilmAI was installed.
10
10
  */
11
11
  const VERSION_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
12
12
  export function installKind(env = process.env, scriptPath = fileURLToPath(import.meta.url)) {
@@ -34,15 +34,17 @@ export function isNewerVersion(latest, current) {
34
34
  return false;
35
35
  }
36
36
  /** The CLI's notice, for a person or an agent reading stderr. */
37
+ /** Release notes: a wilm.ai redirect, so the target can move without a CLI release. */
38
+ export const CHANGES_URL = "https://wilm.ai/changes";
37
39
  export function cliUpdateNotice(current, latest) {
38
- return `Update available: ${current} → ${latest}\nRun "wilma update" to update.`;
40
+ return `Update available: ${current} → ${latest}\nWhat's new: ${CHANGES_URL}\nRun "wilma update" to update.`;
39
41
  }
40
42
  /** The note the MCP server adds for the assistant, who passes it on. */
41
43
  export function mcpUpdateNote(kind, current, latest) {
42
44
  const how = kind === "claude-desktop"
43
45
  ? "download https://wilm.ai/get/claude and open the file; Claude Desktop asks to install it"
44
46
  : 'run "wilma update" in a terminal';
45
- return `Update note: WilmAI ${latest} is available (this computer has ${current}). After answering, tell the user in one sentence that they can update: ${how}.`;
47
+ return `Update note: WilmAI ${latest} is available (this computer has ${current}; what's new: ${CHANGES_URL}). After answering, tell the user in one sentence that they can update: ${how}.`;
46
48
  }
47
49
  function versionCachePath() {
48
50
  return resolve(dirname(getConfigPath()), "version-check.json");
@@ -78,13 +80,13 @@ export function startUpdateCheck() {
78
80
  const response = await fetch("https://registry.npmjs.org/@wilm-ai/wilma-cli/latest", { signal: controller.signal });
79
81
  const data = response.ok ? (await response.json()) : {};
80
82
  const latestVersion = data.version ?? cache?.latestVersion ?? null;
81
- await writeVersionCache({ latestVersion, checkedAt: Date.now() });
83
+ await writeVersionCache({ ...cache, latestVersion, checkedAt: Date.now() });
82
84
  return latestVersion;
83
85
  }
84
86
  catch {
85
87
  // Cancelled because the command finished: try again next time.
86
88
  if (!cancelled)
87
- await writeVersionCache({ latestVersion: cache?.latestVersion ?? null, checkedAt: Date.now() }).catch(() => { });
89
+ await writeVersionCache({ ...cache, latestVersion: cache?.latestVersion ?? null, checkedAt: Date.now() }).catch(() => { });
88
90
  return cache?.latestVersion ?? null;
89
91
  }
90
92
  finally {
@@ -99,6 +101,23 @@ export function startUpdateCheck() {
99
101
  },
100
102
  };
101
103
  }
104
+ /**
105
+ * Whether to show the CLI's notice for `latest` now, and if so, record it: at
106
+ * most once a day, and right away for a version not announced before. An
107
+ * agent's morning run of ten commands should see it once, not ten times.
108
+ */
109
+ export async function claimNotice(latest, now = Date.now()) {
110
+ const cache = await readVersionCache();
111
+ if (cache?.notifiedVersion === latest && now - (cache.notifiedAt ?? 0) < VERSION_CHECK_INTERVAL_MS)
112
+ return false;
113
+ await writeVersionCache({
114
+ latestVersion: cache?.latestVersion ?? latest,
115
+ checkedAt: cache?.checkedAt ?? now,
116
+ notifiedVersion: latest,
117
+ notifiedAt: now,
118
+ });
119
+ return true;
120
+ }
102
121
  /** The latest version if the check has an answer within `waitMs`, else null. */
103
122
  export async function latestWithin(check, waitMs) {
104
123
  let timer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wilm-ai/wilma-cli",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Read your children's Wilma (Finnish school system) from the terminal or an AI assistant: schedule, homework, exams, messages and news.",
5
5
  "license": "MIT",
6
6
  "repository": {