@wirecat/cli-core 0.371.0 → 0.372.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 +25 -0
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.js +2 -1
- package/dist/cli/setup-screen.d.ts +25 -0
- package/dist/cli/setup-screen.js +39 -0
- package/dist/cli/upgrade-command.d.ts +9 -0
- package/dist/cli/upgrade-command.js +26 -0
- package/dist/kit/argv-log.d.ts +4 -0
- package/dist/kit/argv-log.js +9 -0
- package/dist/kit/index.d.ts +1 -0
- package/dist/kit/index.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,31 @@ shape of this file.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.372.0 — 20.10.2026
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Setup wizard helpers from `./cli`**: `AGENTS`, `type Agent`, `screenFor(context, quiet, steps)` and
|
|
15
|
+
`agentFor(context, given, pad, prompt?)`, for the `setup` command of a messenger CLI. `screenFor` prints the
|
|
16
|
+
numbered step headings (`[2/5] …`, details indented by 6) to stderr for a person, hides them under `--quiet`,
|
|
17
|
+
and keeps plain notes in a machine mode. `agentFor` asks which agent to install only at a terminal in the pretty
|
|
18
|
+
format and answers `none` otherwise; an unknown answer is a `validation_error`. Both take the minimum shape they
|
|
19
|
+
read (`format`, `streams.diagnostic`, `renderer.note`, `stdin`), so tg-cli's and whatsapp-cli's contexts fit as they
|
|
20
|
+
are. Pass the wizard's step count as `steps`, and the prompt's `input`, `output` and `signal` as `prompt`
|
|
21
|
+
(`secretInputOf(command)` plus the signal, or `{ input: context.stdin }`). No profile or agent is chosen for the
|
|
22
|
+
caller. This replaces the copies in both CLIs' `src/commands/setup.ts`.
|
|
23
|
+
- **`restartServers(app, script, env, spawn?)` from `./cli`** restarts the `serve` of every profile that is running,
|
|
24
|
+
with `<script> <profile> server restart`, and answers `{ restarted, left }`: the shape `upgradeCommand`'s
|
|
25
|
+
`afterUpdate` port returns, so `afterUpdate: () => restartServers(app, script, env, environment.spawn)` is the whole
|
|
26
|
+
host side. `script` is the new install's own entry point; `spawn` replaces the child process in a test. A serve started
|
|
27
|
+
by hand refuses the restart and lands in `left`. This replaces the copies in both CLIs' `src/commands/update.ts` and
|
|
28
|
+
`src/update.ts`.
|
|
29
|
+
- **`ARGV_LOG` and `argvLogSetup` from `./testing`**: the path `coverage/argv.jsonl` under the working directory, and
|
|
30
|
+
a vitest `globalSetup` function that clears it, for the test matrix that checks which commands and options a run
|
|
31
|
+
drove. A CLI's own `src/testing/argv-log.ts` can go. Vitest takes a package specifier as `globalSetup` only with a
|
|
32
|
+
named `setup` or a default export, so keep a one-line file: `export { argvLogSetup as default } from
|
|
33
|
+
"@wirecat/cli-core/testing"`.
|
|
34
|
+
|
|
10
35
|
## 0.371.0 — 20.10.2026
|
|
11
36
|
|
|
12
37
|
### Added
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -127,7 +127,8 @@ export { createProgram, type ProgramDefinition, type ProgramOptions, type RunOpt
|
|
|
127
127
|
export { fieldsOf, projectFields } from "./result-fields.js";
|
|
128
128
|
export { runsCommand } from "./runs/command.js";
|
|
129
129
|
export { type Config, type Configuration, count, first, flag, fromFile, type GlobalFlags, NONE_NAMED, type ProfileKind, plain, type ResolveOptions, type Settings, type SettingsExtension, type SettingsExtensionContext, type Source, settingsFor, } from "./settings.js";
|
|
130
|
+
export { AGENTS, type Agent, agentFor, screenFor } from "./setup-screen.js";
|
|
130
131
|
export { skillCommand } from "./skill-command.js";
|
|
131
132
|
export { runnable, withSafety } from "./steps.js";
|
|
132
133
|
export { changeStoreSetting, isStoreSetting, STORE_SETTINGS, storeSettings } from "./store-settings.js";
|
|
133
|
-
export { type UpgradeContext, upgradeCommand } from "./upgrade-command.js";
|
|
134
|
+
export { restartServers, type UpgradeContext, upgradeCommand } from "./upgrade-command.js";
|
package/dist/cli/index.js
CHANGED
|
@@ -122,7 +122,8 @@ export { createProgram, run } from "./program.js";
|
|
|
122
122
|
export { fieldsOf, projectFields } from "./result-fields.js";
|
|
123
123
|
export { runsCommand } from "./runs/command.js";
|
|
124
124
|
export { count, first, flag, fromFile, NONE_NAMED, plain, settingsFor, } from "./settings.js";
|
|
125
|
+
export { AGENTS, agentFor, screenFor } from "./setup-screen.js";
|
|
125
126
|
export { skillCommand } from "./skill-command.js";
|
|
126
127
|
export { runnable, withSafety } from "./steps.js";
|
|
127
128
|
export { changeStoreSetting, isStoreSetting, STORE_SETTINGS, storeSettings } from "./store-settings.js";
|
|
128
|
-
export { upgradeCommand } from "./upgrade-command.js";
|
|
129
|
+
export { restartServers, upgradeCommand } from "./upgrade-command.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Renderer, type RenderFormat, type Streams } from "@wirecat/cli-base";
|
|
2
|
+
import { type SecretInput } from "../terminal/prompt.js";
|
|
3
|
+
export declare const AGENTS: readonly ["none", "codex", "cursor", "claude", "gemini", "all"];
|
|
4
|
+
export type Agent = (typeof AGENTS)[number];
|
|
5
|
+
/**
|
|
6
|
+
* A person sees each step as a heading with its details indented under it. `--quiet` hides both, as it
|
|
7
|
+
* hides notes; a machine mode keeps the plain notes it always had, since stderr there is a log.
|
|
8
|
+
*/
|
|
9
|
+
export declare const screenFor: (context: {
|
|
10
|
+
format: RenderFormat;
|
|
11
|
+
streams: Pick<Streams, "diagnostic">;
|
|
12
|
+
renderer: Pick<Renderer, "note">;
|
|
13
|
+
}, quiet: boolean, steps: number) => {
|
|
14
|
+
step: (index: number, title: string) => void;
|
|
15
|
+
detail: (text: string) => void;
|
|
16
|
+
title: (text: string) => void;
|
|
17
|
+
indent: number;
|
|
18
|
+
};
|
|
19
|
+
/** Asks only a person at a terminal; every other run gets "none", so no agent is ever installed unasked. */
|
|
20
|
+
export declare const agentFor: (context: {
|
|
21
|
+
format: RenderFormat;
|
|
22
|
+
stdin: NodeJS.ReadableStream & {
|
|
23
|
+
isTTY?: boolean;
|
|
24
|
+
};
|
|
25
|
+
}, given: Agent | undefined, pad: number, prompt?: Pick<SecretInput, "input" | "output" | "signal">) => Promise<Agent>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CliError, indent } from "@wirecat/cli-base";
|
|
2
|
+
import { readSecret } from "../terminal/prompt.js";
|
|
3
|
+
import { inputPolicy } from "./input-policy.js";
|
|
4
|
+
export const AGENTS = ["none", "codex", "cursor", "claude", "gemini", "all"];
|
|
5
|
+
const DETAIL = 6;
|
|
6
|
+
/**
|
|
7
|
+
* A person sees each step as a heading with its details indented under it. `--quiet` hides both, as it
|
|
8
|
+
* hides notes; a machine mode keeps the plain notes it always had, since stderr there is a log.
|
|
9
|
+
*/
|
|
10
|
+
export const screenFor = (context, quiet, steps) => {
|
|
11
|
+
const person = context.format === "pretty";
|
|
12
|
+
const say = (text) => {
|
|
13
|
+
if (!quiet)
|
|
14
|
+
context.streams.diagnostic(text);
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
step: (index, title) => person ? say(`\n[${index}/${steps}] ${title}`) : context.renderer.note(`${index}/${steps} — ${title}`),
|
|
18
|
+
detail: (text) => (person ? say(indent(text, DETAIL)) : context.renderer.note(text)),
|
|
19
|
+
title: (text) => (person ? say(text) : context.renderer.note(text)),
|
|
20
|
+
indent: person ? DETAIL : 0,
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
/** Asks only a person at a terminal; every other run gets "none", so no agent is ever installed unasked. */
|
|
24
|
+
export const agentFor = async (context, given, pad, prompt = {}) => {
|
|
25
|
+
if (given)
|
|
26
|
+
return given;
|
|
27
|
+
if (context.format !== "pretty" || !context.stdin.isTTY || inputPolicy(context.stdin).noInput)
|
|
28
|
+
return "none";
|
|
29
|
+
const answer = (await readSecret(`${" ".repeat(pad)}Agent [codex/cursor/claude/gemini/all/none] (none): `, {
|
|
30
|
+
...prompt,
|
|
31
|
+
echo: true,
|
|
32
|
+
}))
|
|
33
|
+
.trim()
|
|
34
|
+
.toLowerCase() || "none";
|
|
35
|
+
const agent = AGENTS.find((known) => known === answer);
|
|
36
|
+
if (agent === undefined)
|
|
37
|
+
throw new CliError("validation_error", `unknown agent — choose ${AGENTS.join(", ")} with --agent`);
|
|
38
|
+
return agent;
|
|
39
|
+
};
|
|
@@ -7,4 +7,13 @@ export interface UpgradeContext extends Omit<PackageUpgradePorts, "onInstall"> {
|
|
|
7
7
|
format: RenderFormat;
|
|
8
8
|
streams: Streams;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* A running serve keeps the code it started with; the update replaced the files under it. Each is restarted by
|
|
12
|
+
* the new `script` — `server restart` refuses a serve started by hand, which is then named in `left`.
|
|
13
|
+
* `spawn` replaces the child process, as in `UpdateEnvironment`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const restartServers: (app: AppIdentity, script: string, env: NodeJS.ProcessEnv, spawn?: (argv: string[]) => number) => {
|
|
16
|
+
restarted: string[];
|
|
17
|
+
left: string[];
|
|
18
|
+
};
|
|
10
19
|
export declare const upgradeCommand: (app: AppIdentity, packageName: string, contextFor: (command: Command) => UpgradeContext) => Command;
|
|
@@ -1,9 +1,35 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
1
2
|
import { CliError } from "@wirecat/cli-base";
|
|
2
3
|
import { annotate } from "@wirecat/cli-base/commands";
|
|
3
4
|
import { Command } from "commander";
|
|
5
|
+
import { servingProfiles } from "../background/lock.js";
|
|
4
6
|
import { upgradePackage } from "../services/package-upgrade.js";
|
|
5
7
|
import { grantsAuthority, LOCAL_WRITE } from "./effects.js";
|
|
6
8
|
import { itemOf, renderAnswer, snakeKeys } from "./envelope.js";
|
|
9
|
+
import { usableProfileName } from "./profile.js";
|
|
10
|
+
/**
|
|
11
|
+
* A running serve keeps the code it started with; the update replaced the files under it. Each is restarted by
|
|
12
|
+
* the new `script` — `server restart` refuses a serve started by hand, which is then named in `left`.
|
|
13
|
+
* `spawn` replaces the child process, as in `UpdateEnvironment`.
|
|
14
|
+
*/
|
|
15
|
+
export const restartServers = (app, script, env, spawn) => {
|
|
16
|
+
const restarted = [];
|
|
17
|
+
const left = [];
|
|
18
|
+
for (const profile of servingProfiles(app, env)) {
|
|
19
|
+
try {
|
|
20
|
+
usableProfileName(profile);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const argv = [script, profile, "server", "restart"];
|
|
26
|
+
const code = spawn
|
|
27
|
+
? spawn([process.execPath, ...argv])
|
|
28
|
+
: (spawnSync(process.execPath, argv, { env, shell: false, stdio: ["ignore", 2, 2] }).status ?? 1);
|
|
29
|
+
(code === 0 ? restarted : left).push(profile);
|
|
30
|
+
}
|
|
31
|
+
return { restarted, left };
|
|
32
|
+
};
|
|
7
33
|
export const upgradeCommand = (app, packageName, contextFor) => grantsAuthority(annotate(new Command("upgrade"), {
|
|
8
34
|
effects: LOCAL_WRITE,
|
|
9
35
|
mcp: false,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { mkdirSync, rmSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/** Where each test run records which commands and options it drove (`pnpm test:matrix`). */
|
|
4
|
+
export const ARGV_LOG = join(process.cwd(), "coverage", "argv.jsonl");
|
|
5
|
+
/** A vitest `globalSetup`: one run, one log. */
|
|
6
|
+
export const argvLogSetup = () => {
|
|
7
|
+
mkdirSync(join(process.cwd(), "coverage"), { recursive: true });
|
|
8
|
+
rmSync(ARGV_LOG, { force: true });
|
|
9
|
+
};
|
package/dist/kit/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { ARGV_LOG, argvLogSetup } from "./argv-log.js";
|
|
1
2
|
export { type ContractCase, type ContractOptions, contractCases, OPTIONAL_METHODS } from "./contract.js";
|
|
2
3
|
export { type FakeAdapter, fakeAdapter } from "./fake.js";
|
|
3
4
|
export { type McpStdio, type McpStdioStreams, type McpToolResult, mcpOverStdio } from "./mcp-stdio.js";
|
package/dist/kit/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wirecat/cli-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.372.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",
|