@wirecat/cli-core 0.561.0 → 0.562.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 CHANGED
@@ -5,7 +5,23 @@ Notable changes to `@wirecat/cli-core` (`@wirecat/cli-messaging` up to 0.261.0,
5
5
  minor version may break callers, and says how under "Changed — may break callers". `pnpm docs:check` checks the
6
6
  shape of this file.
7
7
 
8
- ## Unreleased
8
+ ## 0.562.0 — 03.11.2026
9
+
10
+ ### Added
11
+
12
+ - **A CLI can write each of its settings into its config file with the default, so the owner sees every setting
13
+ there.** A CLI declares its scalar settings as `DeclaredSetting` (`key`, `default`, `description`).
14
+ `withSettingDefaults(raw, declared)` returns the file with each missing setting added at its default. It keeps the
15
+ owner's values, their order and unknown keys. It does not create a section that is not there.
16
+ `settingRows(raw, declared)` gives `config show` each setting with its value, default, description and `from`
17
+ (`config file` or `default`). memo is the first user (cli-base WC-CMD-30).
18
+ - **`KEEP_SUCCESSFUL_RUNS_FOR_DAYS` and `RUNS_SIZE_LIMIT_MB` are exported** beside `KEEP_RUNS_FOR_DAYS`. A host can
19
+ then name the run-record defaults it writes into its config file.
20
+
21
+ ### Fixed
22
+
23
+ - **The shared `doctor` (`appDoctorCommand`) answers with the clock:** `meta.now`, `meta.now_local` and
24
+ `meta.timezone`, as a setup check should (WC-TIME-7). A CLI that kept its own doctor for this can use the shared one.
9
25
 
10
26
  ## 0.561.0 — 03.11.2026
11
27
 
@@ -2,6 +2,8 @@ import { existsSync } from "node:fs";
2
2
  import { dirname, resolve } from "node:path";
3
3
  import { CliError, configFilePath, resolvePaths } from "@wirecat/cli-base";
4
4
  import { annotate } from "@wirecat/cli-base/commands";
5
+ import { timezoneOf } from "@wirecat/cli-base/query";
6
+ import { clockMeta } from "@wirecat/cli-base/standards";
5
7
  import { isNewer, latestVersion } from "@wirecat/cli-base/update";
6
8
  import { Command } from "commander";
7
9
  import { envName, readOnlyLockOf } from "../ports/app.js";
@@ -149,7 +151,7 @@ export const appDoctorCommand = (app, configuration, options = {}) => profileFre
149
151
  ? await onlineCheck(app, env, environment.fetch ?? fetch, options)
150
152
  : undefined;
151
153
  const output = outputFor(this);
152
- renderAnswer(this, output, itemOf({ ...report, ...local.fields, ...(online ? { online } : {}) }));
154
+ renderAnswer(this, output, itemOf({ ...report, ...local.fields, ...(online ? { online } : {}) }, { meta: clockMeta(Date.now(), timezoneOf()) }));
153
155
  for (const fix of fixes)
154
156
  output.renderer.note(`to make it private: ${fix}`);
155
157
  for (const note of local.notes)
@@ -26,7 +26,7 @@ export { type CacheEvent, type DiagnosticEvent, type EventSink, providerErrorKey
26
26
  export { CORE_LOG_EVENTS } from "../runs/log-events.js";
27
27
  export { openProviderLog, PROVIDER_LOG_BYTES, type ProviderWarnings, providerLogPathFor, providerWarnings, writeProviderWarning, } from "../runs/provider-log.js";
28
28
  export { crashOf, type Recording, type RecordingOptions, recorded, startRecording, wasSettled, } from "../runs/recording.js";
29
- export { findRun, KEEP_RUNS_FOR_DAYS, listRuns, pruneRuns, type RunContext, type RunMetadata, readEvents, runsDirFor, runtime, startRun, } from "../runs/run.js";
29
+ export { findRun, KEEP_RUNS_FOR_DAYS, KEEP_SUCCESSFUL_RUNS_FOR_DAYS, listRuns, pruneRuns, RUNS_SIZE_LIMIT_MB, type RunContext, type RunMetadata, readEvents, runsDirFor, runtime, startRun, } from "../runs/run.js";
30
30
  export { runContextOf, secretInput } from "../runs/run-context.js";
31
31
  export { type Attempt, currentAttempt, currentRun, inRun, type RunScope, runEvent, useAsProcessRun, withAttempt, } from "../runs/scope.js";
32
32
  export { LANGUAGES } from "../search/languages.js";
@@ -119,6 +119,7 @@ export { type ProjectStatusHints, type ProjectStatusItem, projectStatusAnswer, p
119
119
  export { STATUS_ROWS, STATUS_SIGNAL_ROWS } from "./project-status-rows.js";
120
120
  export { fieldsOf, projectFields } from "./result-fields.js";
121
121
  export type { ScheduleHost } from "./schedule/schedule-command.js";
122
+ export { type DeclaredSetting, type SettingRow, settingRows, withSettingDefaults } from "./setting-defaults.js";
122
123
  export { type Config, type Configuration, count, first, flag, fromFile, type GlobalFlags, NONE_NAMED, namedProfile, type ProfileKind, plain, type ResolveOptions, type Settings, type SettingsExtension, type SettingsExtensionContext, type Source, settingsFor, } from "./settings.js";
123
124
  export { type PermissionAnswer, readSetupAnswers, type SetupAnswers, setupPermissionCeiling } from "./setup-answers.js";
124
125
  export { AGENTS, type Agent, agentFor, screenFor } from "./setup-screen.js";
package/dist/cli/index.js CHANGED
@@ -22,7 +22,7 @@ export { providerErrorKey, renderEvent, } from "../runs/events.js";
22
22
  export { CORE_LOG_EVENTS } from "../runs/log-events.js";
23
23
  export { openProviderLog, PROVIDER_LOG_BYTES, providerLogPathFor, providerWarnings, writeProviderWarning, } from "../runs/provider-log.js";
24
24
  export { crashOf, recorded, startRecording, wasSettled, } from "../runs/recording.js";
25
- export { findRun, KEEP_RUNS_FOR_DAYS, listRuns, pruneRuns, readEvents, runsDirFor, runtime, startRun, } from "../runs/run.js";
25
+ export { findRun, KEEP_RUNS_FOR_DAYS, KEEP_SUCCESSFUL_RUNS_FOR_DAYS, listRuns, pruneRuns, RUNS_SIZE_LIMIT_MB, readEvents, runsDirFor, runtime, startRun, } from "../runs/run.js";
26
26
  export { runContextOf, secretInput } from "../runs/run-context.js";
27
27
  export { currentAttempt, currentRun, inRun, runEvent, useAsProcessRun, withAttempt, } from "../runs/scope.js";
28
28
  export { LANGUAGES } from "../search/languages.js";
@@ -108,6 +108,7 @@ export { projectAnswerParts, projectCutoffTime, projectEvidenceText, projectWind
108
108
  export { projectStatusAnswer, projectStatusRow, projectStatusSchema, projectStatusText, } from "./project-status.js";
109
109
  export { STATUS_ROWS, STATUS_SIGNAL_ROWS } from "./project-status-rows.js";
110
110
  export { fieldsOf, projectFields } from "./result-fields.js";
111
+ export { settingRows, withSettingDefaults } from "./setting-defaults.js";
111
112
  export { count, first, flag, fromFile, NONE_NAMED, namedProfile, plain, settingsFor, } from "./settings.js";
112
113
  export { readSetupAnswers, setupPermissionCeiling } from "./setup-answers.js";
113
114
  export { AGENTS, agentFor, screenFor } from "./setup-screen.js";
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A scalar setting a CLI writes into its config file with its default, so the owner finds and edits it there without
3
+ * reading the docs (WC-CMD-30). Never declare a secret: `config show` prints every declared value.
4
+ */
5
+ export interface DeclaredSetting {
6
+ /** The dotted path in the file. A nested setting is written only where its section already exists. */
7
+ key: string;
8
+ default: string | number | boolean;
9
+ description: string;
10
+ }
11
+ export interface SettingRow {
12
+ setting: string;
13
+ value: unknown;
14
+ default: string | number | boolean;
15
+ from: "config file" | "default";
16
+ description: string;
17
+ }
18
+ /**
19
+ * The file with every declared setting it lacks, at its default. What the owner wrote stays as written, in its order,
20
+ * unknown keys included; a section that is not there is not created, since it may need fields no default can give.
21
+ */
22
+ export declare const withSettingDefaults: (raw: unknown, declared: readonly DeclaredSetting[]) => {
23
+ config: unknown;
24
+ added: string[];
25
+ };
26
+ /** Every declared setting with what holds and whether the file says it, for `config show`. */
27
+ export declare const settingRows: (raw: unknown, declared: readonly DeclaredSetting[]) => SettingRow[];
@@ -0,0 +1,36 @@
1
+ const isNode = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2
+ const parentOf = (config, key) => {
3
+ const path = key.split(".");
4
+ const leaf = path.pop();
5
+ return { node: path.reduce((node, part) => (isNode(node) ? node[part] : undefined), config), leaf };
6
+ };
7
+ /**
8
+ * The file with every declared setting it lacks, at its default. What the owner wrote stays as written, in its order,
9
+ * unknown keys included; a section that is not there is not created, since it may need fields no default can give.
10
+ */
11
+ export const withSettingDefaults = (raw, declared) => {
12
+ if (raw !== undefined && !isNode(raw))
13
+ return { config: raw, added: [] };
14
+ const config = raw === undefined ? {} : structuredClone(raw);
15
+ const added = [];
16
+ for (const setting of declared) {
17
+ const { node, leaf } = parentOf(config, setting.key);
18
+ if (!isNode(node) || Object.hasOwn(node, leaf))
19
+ continue;
20
+ node[leaf] = setting.default;
21
+ added.push(setting.key);
22
+ }
23
+ return { config, added };
24
+ };
25
+ /** Every declared setting with what holds and whether the file says it, for `config show`. */
26
+ export const settingRows = (raw, declared) => declared.map((setting) => {
27
+ const { node, leaf } = isNode(raw) ? parentOf(raw, setting.key) : { node: undefined, leaf: "" };
28
+ const written = isNode(node) && Object.hasOwn(node, leaf);
29
+ return {
30
+ setting: setting.key,
31
+ value: written ? node[leaf] : setting.default,
32
+ default: setting.default,
33
+ from: written ? "config file" : "default",
34
+ description: setting.description,
35
+ };
36
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.561.0",
3
+ "version": "0.562.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",