@wirecat/cli-core 0.360.0 → 0.361.0
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/CHANGELOG.md +14 -0
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/messenger/context.js +13 -12
- package/dist/cli/messenger/serve-notice.d.ts +3 -2
- package/dist/cli/messenger/serve-notice.js +6 -4
- package/dist/cli/messenger/stored.d.ts +2 -2
- package/dist/cli/messenger/stored.js +14 -6
- package/dist/runs/events.d.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ shape of this file.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.361.0 — 19.10.2026
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **A warning in `serve`'s log now says which warning it was.** Off a terminal, a re-key given up at exit, a write
|
|
15
|
+
the store did not take, a passive listen that failed and a stored-chats call that failed each wrote a bare
|
|
16
|
+
`serve.warning` record, so the log could not tell them apart. The record now carries the warning's `code`,
|
|
17
|
+
`operation` and `counts` (`rekeys_not_applied` with `counts.rekeys`), never its sentence, which can quote an
|
|
18
|
+
error or a chat. Warnings that have no code yet still log a bare record.
|
|
19
|
+
- **The adapter test example in [ADAPTERS.md](docs/dev/ADAPTERS.md#running-the-contract-cases) no longer gives up
|
|
20
|
+
re-keys.** It handed `run()` `rekeyPacing: { lockMs: 0 }`, one re-key per transaction, so a few hundred re-keys
|
|
21
|
+
outlasted `closeWaitMs: 10` and were given up. It now hands `{ lockMs: 1000, pauseMs: 0 }` and says what each
|
|
22
|
+
field does.
|
|
23
|
+
|
|
10
24
|
## 0.360.0 — 19.10.2026
|
|
11
25
|
|
|
12
26
|
### Added
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface BaseEnvironment {
|
|
|
37
37
|
storeLockWaitMs?: number;
|
|
38
38
|
/** How long a connection's close waits on its saves and passive listens, 5 s unless a test hands one in. */
|
|
39
39
|
closeWaitMs?: number;
|
|
40
|
-
/** How long one pass of chat re-keys holds the store's write lock and the pause after it; tests hand in
|
|
40
|
+
/** How long one pass of chat re-keys holds the store's write lock and the pause after it; tests hand in no pause. */
|
|
41
41
|
rekeyPacing?: {
|
|
42
42
|
lockMs: number;
|
|
43
43
|
pauseMs: number;
|
|
@@ -126,8 +126,9 @@ const listened = ({ run, operation, what }, events, warn, waitMs) => {
|
|
|
126
126
|
.catch((error) => {
|
|
127
127
|
if (closing)
|
|
128
128
|
return;
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
const warning = { event: "warning", code: "listen_failed", operation };
|
|
130
|
+
events(warning);
|
|
131
|
+
warn(`${what} arriving during this command are not saved: ${error instanceof Error ? error.message : String(error)}`, warning);
|
|
131
132
|
});
|
|
132
133
|
return {
|
|
133
134
|
operation,
|
|
@@ -230,22 +231,22 @@ export const connected = (connection, { app, provider, name, deletedWithoutChat,
|
|
|
230
231
|
finally {
|
|
231
232
|
try {
|
|
232
233
|
const ended = await Promise.all(passives.map((passive) => passive.stop()));
|
|
234
|
+
const warn = renderer.warn;
|
|
235
|
+
const warned = (warning, text) => {
|
|
236
|
+
events(warning);
|
|
237
|
+
warn(text, warning);
|
|
238
|
+
};
|
|
233
239
|
passives.forEach(({ operation, what }, at) => {
|
|
234
240
|
if (ended[at])
|
|
235
241
|
return;
|
|
236
|
-
|
|
237
|
-
renderer.warn(`not saved to the local store: the messenger was still handing on ${what} at exit`);
|
|
242
|
+
warned({ event: "warning", code: "store_not_written", operation }, `not saved to the local store: the messenger was still handing on ${what} at exit`);
|
|
238
243
|
});
|
|
239
244
|
await settled(new Set([...pending, ...announcing]), closeWaitMs);
|
|
240
245
|
closing.abort();
|
|
241
|
-
if (pending.size > 0)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (announcing.size > 0) {
|
|
246
|
-
events({ event: "warning", code: "stored_chats_failed", operation: "close" });
|
|
247
|
-
renderer.warn("the messenger's stored-chats hook did not finish and was abandoned at exit; nothing is lost");
|
|
248
|
-
}
|
|
246
|
+
if (pending.size > 0)
|
|
247
|
+
warned({ event: "warning", code: "store_not_written", operation: "close" }, "not saved to the local store: the last messages were still being written at exit");
|
|
248
|
+
if (announcing.size > 0)
|
|
249
|
+
warned({ event: "warning", code: "stored_chats_failed", operation: "close" }, "the messenger's stored-chats hook did not finish and was abandoned at exit; nothing is lost");
|
|
249
250
|
}
|
|
250
251
|
finally {
|
|
251
252
|
await store.close();
|
|
@@ -13,8 +13,9 @@ export declare const noticeFor: (context: MessengerContext, app: AppIdentity, se
|
|
|
13
13
|
/**
|
|
14
14
|
* A serve left running writes its diagnostics to a log file, so off a terminal each one is a log record with
|
|
15
15
|
* its time and run. A sentence handed to the renderer may quote an error or a chat, so the record keeps only
|
|
16
|
-
* which kind of line it was
|
|
17
|
-
*
|
|
16
|
+
* which kind of line it was, and a warning's code, operation and counts when the warning event comes with it
|
|
17
|
+
* (`Warn`); serve's own reports go through `noticeFor` with a code. The renderer is changed in place, so the
|
|
18
|
+
* send guard, bound to it before serve started, writes records too.
|
|
18
19
|
*/
|
|
19
20
|
export declare const recordDiagnostics: (context: MessengerContext, app: AppIdentity) => MessengerContext;
|
|
20
21
|
export {};
|
|
@@ -19,16 +19,18 @@ export const noticeFor = (context, app, severity = "warn") => ({ text, ...attrib
|
|
|
19
19
|
/**
|
|
20
20
|
* A serve left running writes its diagnostics to a log file, so off a terminal each one is a log record with
|
|
21
21
|
* its time and run. A sentence handed to the renderer may quote an error or a chat, so the record keeps only
|
|
22
|
-
* which kind of line it was
|
|
23
|
-
*
|
|
22
|
+
* which kind of line it was, and a warning's code, operation and counts when the warning event comes with it
|
|
23
|
+
* (`Warn`); serve's own reports go through `noticeFor` with a code. The renderer is changed in place, so the
|
|
24
|
+
* send guard, bound to it before serve started, writes records too.
|
|
24
25
|
*/
|
|
25
26
|
export const recordDiagnostics = (context, app) => {
|
|
26
27
|
if (context.format === "pretty")
|
|
27
28
|
return context;
|
|
28
|
-
const say = (severity, event, always = false) => (_text) => {
|
|
29
|
+
const say = (severity, event, always = false) => (_text, warning) => {
|
|
29
30
|
if (context.settings.quiet && !always)
|
|
30
31
|
return;
|
|
31
|
-
|
|
32
|
+
const { event: _warning, ...fields } = warning ?? {};
|
|
33
|
+
record(context, app, severity, { event, ...fields });
|
|
32
34
|
};
|
|
33
35
|
const renderer = context.renderer;
|
|
34
36
|
renderer.note = say("info", "serve.note");
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { Id } from "../../domain/models.js";
|
|
2
2
|
import { type MessengerAdapter } from "../../ports/messenger.js";
|
|
3
3
|
import type { MessengerTraits } from "../../ports/traits.js";
|
|
4
|
-
import type { EventSink } from "../../runs/events.js";
|
|
4
|
+
import type { EventSink, Warn } from "../../runs/events.js";
|
|
5
5
|
import type { AccountKey, DeletionScope, MessageStore } from "../../store/store.js";
|
|
6
6
|
export interface Saving {
|
|
7
7
|
account: AccountKey;
|
|
8
8
|
/** Opened on the first save, not before: a command that reads nothing has no reason to touch the file. */
|
|
9
9
|
store: () => Promise<MessageStore | undefined>;
|
|
10
|
-
warn:
|
|
10
|
+
warn: Warn;
|
|
11
11
|
events: EventSink;
|
|
12
12
|
/** Saves still writing, for the closer to wait on: `watch` does not hold the next event for one. */
|
|
13
13
|
pending?: Set<Promise<void>>;
|
|
@@ -16,9 +16,10 @@ export const stored = (messenger, { account, store, warn, events, pending, annou
|
|
|
16
16
|
let warned = false;
|
|
17
17
|
let recorded = profile === undefined;
|
|
18
18
|
const notWritten = (operation, error) => {
|
|
19
|
-
|
|
19
|
+
const warning = { event: "warning", code: "store_not_written", operation };
|
|
20
|
+
events(warning);
|
|
20
21
|
if (!warned)
|
|
21
|
-
warn(`not saved to the local store: ${error instanceof Error ? error.message : String(error)}
|
|
22
|
+
warn(`not saved to the local store: ${error instanceof Error ? error.message : String(error)}`, warning);
|
|
22
23
|
warned = true;
|
|
23
24
|
};
|
|
24
25
|
const attempt = async (operation, write) => {
|
|
@@ -92,8 +93,14 @@ export const stored = (messenger, { account, store, warn, events, pending, annou
|
|
|
92
93
|
pending?.delete(saving);
|
|
93
94
|
if (count === 0)
|
|
94
95
|
return;
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
const warning = {
|
|
97
|
+
event: "warning",
|
|
98
|
+
code: "rekeys_not_applied",
|
|
99
|
+
operation: "history.rekey",
|
|
100
|
+
counts: { rekeys: count },
|
|
101
|
+
};
|
|
102
|
+
events(warning);
|
|
103
|
+
warn(`${count} chat re-key${count === 1 ? "" : "s"} not applied yet; the next serve applies them`, warning);
|
|
97
104
|
};
|
|
98
105
|
closing?.addEventListener("abort", giveUpRekeys, { once: true });
|
|
99
106
|
const saveRekeys = async (pairs, round) => {
|
|
@@ -466,8 +473,9 @@ const announceStoredChats = async (messenger, store, account, events, warn, reci
|
|
|
466
473
|
await messenger.storedChats?.(held);
|
|
467
474
|
}
|
|
468
475
|
catch (error) {
|
|
469
|
-
|
|
470
|
-
|
|
476
|
+
const warning = { event: "warning", code: "stored_chats_failed", operation: "history.stored_chats" };
|
|
477
|
+
events(warning);
|
|
478
|
+
warn(`the messenger was not told the stored chats: ${error instanceof Error ? error.message : String(error)}`, warning);
|
|
471
479
|
}
|
|
472
480
|
};
|
|
473
481
|
/** Read once when `watch` starts: a store read per event would let a later event overtake an earlier one. */
|
package/dist/runs/events.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ export interface CacheEvent {
|
|
|
49
49
|
}
|
|
50
50
|
export type DiagnosticEvent = RequestEvent | CacheEvent | WarningEvent;
|
|
51
51
|
export type EventSink = (event: DiagnosticEvent) => void;
|
|
52
|
+
/** A sentence for a person, and the warning event it stands for when there is one: a log record keeps only the event. */
|
|
53
|
+
export type Warn = (message: string, warning?: WarningEvent) => void;
|
|
52
54
|
/** `FLOOD_WAIT`, `PEER_ID_INVALID`, `login.token` — or nothing. A sentence is dropped, not trimmed. */
|
|
53
55
|
export declare const providerErrorKey: (value: unknown) => string | undefined;
|
|
54
56
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wirecat/cli-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.361.0",
|
|
4
4
|
"description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Viacheslav Ptsarev",
|