toolcraft 0.0.39 → 0.0.40
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 +41 -4
- package/dist/cli.js +40 -9
- package/dist/http-errors.d.ts +57 -0
- package/dist/http-errors.js +72 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +15 -0
- package/dist/mcp-proxy.js +16 -1
- package/dist/mcp.js +224 -12
- package/node_modules/@poe-code/frontmatter/README.md +35 -0
- package/node_modules/@poe-code/frontmatter/dist/fences.d.ts +8 -0
- package/node_modules/@poe-code/frontmatter/dist/fences.js +72 -0
- package/node_modules/@poe-code/frontmatter/dist/index.d.ts +3 -0
- package/node_modules/@poe-code/frontmatter/dist/index.js +3 -0
- package/node_modules/@poe-code/frontmatter/dist/parse.d.ts +20 -0
- package/node_modules/@poe-code/frontmatter/dist/parse.js +137 -0
- package/node_modules/@poe-code/frontmatter/dist/stringify.d.ts +1 -0
- package/node_modules/@poe-code/frontmatter/dist/stringify.js +35 -0
- package/node_modules/@poe-code/frontmatter/package.json +25 -0
- package/node_modules/mcp-oauth/dist/server/jwks-token-verifier.d.ts +1 -0
- package/node_modules/mcp-oauth/dist/server/jwks-token-verifier.js +25 -1
- package/node_modules/tiny-mcp-client/README.md +7 -0
- package/node_modules/tiny-mcp-client/dist/internal.d.ts +2 -0
- package/node_modules/tiny-mcp-client/dist/internal.js +3 -0
- package/node_modules/tiny-mcp-client/dist/mcp-tool-types.compile-check.js +10 -0
- package/node_modules/tiny-mcp-client/src/http-oauth.test.ts +2 -8
- package/node_modules/tiny-mcp-client/src/internal.ts +6 -0
- package/node_modules/tiny-mcp-client/src/mcp-tool-types.compile-check.ts +10 -0
- package/node_modules/toolcraft-design/README.md +12 -0
- package/node_modules/toolcraft-design/dist/prompts/index.d.ts +39 -14
- package/node_modules/toolcraft-design/dist/prompts/index.js +10 -6
- package/node_modules/toolcraft-design/dist/prompts/interactive/cancel-symbol.d.ts +2 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/cancel-symbol.js +4 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/confirm.d.ts +9 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/confirm.js +47 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/core.d.ts +55 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/core.js +274 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/glyphs.d.ts +20 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/glyphs.js +53 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/index.d.ts +6 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/index.js +6 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/keys.d.ts +2 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/keys.js +28 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/multiselect.d.ts +13 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/multiselect.js +131 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/pagination.d.ts +10 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/pagination.js +52 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/password.d.ts +10 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/password.js +55 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/select.d.ts +18 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/select.js +89 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/test-helpers.d.ts +21 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/test-helpers.js +32 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/text.d.ts +12 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/text.js +60 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/wrap.d.ts +4 -0
- package/node_modules/toolcraft-design/dist/prompts/interactive/wrap.js +18 -0
- package/node_modules/toolcraft-design/dist/prompts/primitives/cancel.d.ts +1 -1
- package/node_modules/toolcraft-design/dist/prompts/primitives/cancel.js +1 -1
- package/node_modules/toolcraft-design/dist/terminal-markdown/parser/frontmatter.js +20 -453
- package/node_modules/toolcraft-design/package.json +6 -3
- package/package.json +9 -6
|
@@ -243,16 +243,40 @@ export function createJwksTokenVerifier(options) {
|
|
|
243
243
|
const jwksUrl = toUrl(options.jwksUrl, "jwksUrl");
|
|
244
244
|
const clockSkewSeconds = options.clockSkewSeconds ?? 30;
|
|
245
245
|
const allowedAlgorithms = options.allowedAlgorithms ?? DEFAULT_ALLOWED_ALGORITHMS;
|
|
246
|
+
const jwksCacheTtlMs = options.jwksCacheTtlMs ?? 300_000;
|
|
246
247
|
const fetchImplementation = options.fetch ?? globalThis.fetch;
|
|
248
|
+
let cachedJwks;
|
|
249
|
+
let pendingJwks;
|
|
247
250
|
if (typeof fetchImplementation !== "function") {
|
|
248
251
|
throw new Error("fetch is not available; pass options.fetch explicitly");
|
|
249
252
|
}
|
|
253
|
+
async function getJwks() {
|
|
254
|
+
const now = Date.now();
|
|
255
|
+
if (cachedJwks !== undefined && cachedJwks.expiresAt > now) {
|
|
256
|
+
return cachedJwks.value;
|
|
257
|
+
}
|
|
258
|
+
if (pendingJwks !== undefined) {
|
|
259
|
+
return pendingJwks;
|
|
260
|
+
}
|
|
261
|
+
pendingJwks = loadJwks(jwksUrl, fetchImplementation)
|
|
262
|
+
.then((jwks) => {
|
|
263
|
+
cachedJwks = {
|
|
264
|
+
value: jwks,
|
|
265
|
+
expiresAt: Date.now() + jwksCacheTtlMs,
|
|
266
|
+
};
|
|
267
|
+
return jwks;
|
|
268
|
+
})
|
|
269
|
+
.finally(() => {
|
|
270
|
+
pendingJwks = undefined;
|
|
271
|
+
});
|
|
272
|
+
return pendingJwks;
|
|
273
|
+
}
|
|
250
274
|
return {
|
|
251
275
|
async verify(input) {
|
|
252
276
|
const expectedResource = canonicalizeResourceIndicator(input.resource);
|
|
253
277
|
const algorithm = resolveAlgorithm(input.token, allowedAlgorithms);
|
|
254
278
|
try {
|
|
255
|
-
const jwks = await
|
|
279
|
+
const jwks = await getJwks();
|
|
256
280
|
const verified = await verifyJwtAgainstJwks({
|
|
257
281
|
token: input.token,
|
|
258
282
|
jwks,
|
|
@@ -14,9 +14,16 @@ const client = new McpClient({
|
|
|
14
14
|
await client.connect(new HttpTransport({ url: "http://127.0.0.1:3000/mcp" }));
|
|
15
15
|
const tools = await client.listTools();
|
|
16
16
|
console.log(tools);
|
|
17
|
+
const result = await client.callTool({
|
|
18
|
+
name: "search",
|
|
19
|
+
arguments: { query: "typed outputs" },
|
|
20
|
+
});
|
|
21
|
+
console.log(result.structuredContent);
|
|
17
22
|
await client.close();
|
|
18
23
|
```
|
|
19
24
|
|
|
25
|
+
`Tool` includes MCP `outputSchema` when a server advertises typed tool output. `CallToolResult` includes `structuredContent?: Record<string, unknown>` for typed results; legacy/content-block tools still use `content[]`.
|
|
26
|
+
|
|
20
27
|
## Transports
|
|
21
28
|
|
|
22
29
|
| Transport | Description |
|
|
@@ -123,6 +123,7 @@ export interface Tool {
|
|
|
123
123
|
name: string;
|
|
124
124
|
description?: string;
|
|
125
125
|
inputSchema: Record<string, unknown>;
|
|
126
|
+
outputSchema?: Record<string, unknown>;
|
|
126
127
|
annotations?: ToolAnnotations;
|
|
127
128
|
}
|
|
128
129
|
export interface ToolAnnotations {
|
|
@@ -216,6 +217,7 @@ export interface GetPromptParams {
|
|
|
216
217
|
}
|
|
217
218
|
export interface CallToolResult {
|
|
218
219
|
content: ContentItem[];
|
|
220
|
+
structuredContent?: Record<string, unknown>;
|
|
219
221
|
isError?: boolean;
|
|
220
222
|
}
|
|
221
223
|
export interface Root {
|
|
@@ -2421,6 +2421,9 @@ function isCallToolResult(value) {
|
|
|
2421
2421
|
if (!isObjectRecord(value) || !Array.isArray(value.content)) {
|
|
2422
2422
|
return false;
|
|
2423
2423
|
}
|
|
2424
|
+
if (value.structuredContent !== undefined && !isObjectRecord(value.structuredContent)) {
|
|
2425
|
+
return false;
|
|
2426
|
+
}
|
|
2424
2427
|
if (value.isError !== undefined && typeof value.isError !== "boolean") {
|
|
2425
2428
|
return false;
|
|
2426
2429
|
}
|
|
@@ -14,6 +14,13 @@ const tool = {
|
|
|
14
14
|
locale: { type: "string" },
|
|
15
15
|
},
|
|
16
16
|
},
|
|
17
|
+
outputSchema: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
word: { type: "string" },
|
|
21
|
+
},
|
|
22
|
+
required: ["word"],
|
|
23
|
+
},
|
|
17
24
|
annotations,
|
|
18
25
|
};
|
|
19
26
|
const callToolParams = {
|
|
@@ -52,6 +59,9 @@ const contentItems = [
|
|
|
52
59
|
];
|
|
53
60
|
const callToolResult = {
|
|
54
61
|
content: contentItems,
|
|
62
|
+
structuredContent: {
|
|
63
|
+
word: "quotidian",
|
|
64
|
+
},
|
|
55
65
|
};
|
|
56
66
|
const callToolErrorResult = {
|
|
57
67
|
content: [textContent],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import http from "node:http";
|
|
2
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { nodeFetch } from "tiny-http-mcp-server/testing";
|
|
3
3
|
import type { OAuthSessionStore, StoredOAuthSession } from "mcp-oauth";
|
|
4
4
|
import {
|
|
5
5
|
HttpTransport,
|
|
@@ -918,11 +918,5 @@ function readTransportLine(transport: HttpTransport): Promise<string> {
|
|
|
918
918
|
}
|
|
919
919
|
|
|
920
920
|
async function requestLoopbackCallback(url: string): Promise<void> {
|
|
921
|
-
await
|
|
922
|
-
const request = http.get(url, (response) => {
|
|
923
|
-
response.resume();
|
|
924
|
-
response.once("end", resolve);
|
|
925
|
-
});
|
|
926
|
-
request.once("error", reject);
|
|
927
|
-
});
|
|
921
|
+
await nodeFetch(url);
|
|
928
922
|
}
|
|
@@ -670,6 +670,7 @@ export interface Tool {
|
|
|
670
670
|
name: string;
|
|
671
671
|
description?: string;
|
|
672
672
|
inputSchema: Record<string, unknown>;
|
|
673
|
+
outputSchema?: Record<string, unknown>;
|
|
673
674
|
annotations?: ToolAnnotations;
|
|
674
675
|
}
|
|
675
676
|
|
|
@@ -785,6 +786,7 @@ export interface GetPromptParams {
|
|
|
785
786
|
|
|
786
787
|
export interface CallToolResult {
|
|
787
788
|
content: ContentItem[];
|
|
789
|
+
structuredContent?: Record<string, unknown>;
|
|
788
790
|
isError?: boolean;
|
|
789
791
|
}
|
|
790
792
|
|
|
@@ -3578,6 +3580,10 @@ function isCallToolResult(value: unknown): value is CallToolResult {
|
|
|
3578
3580
|
return false;
|
|
3579
3581
|
}
|
|
3580
3582
|
|
|
3583
|
+
if (value.structuredContent !== undefined && !isObjectRecord(value.structuredContent)) {
|
|
3584
|
+
return false;
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3581
3587
|
if (value.isError !== undefined && typeof value.isError !== "boolean") {
|
|
3582
3588
|
return false;
|
|
3583
3589
|
}
|
|
@@ -28,6 +28,13 @@ const tool: Tool = {
|
|
|
28
28
|
locale: { type: "string" },
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
|
+
outputSchema: {
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
word: { type: "string" },
|
|
35
|
+
},
|
|
36
|
+
required: ["word"],
|
|
37
|
+
},
|
|
31
38
|
annotations,
|
|
32
39
|
};
|
|
33
40
|
|
|
@@ -74,6 +81,9 @@ const contentItems: ContentItem[] = [
|
|
|
74
81
|
|
|
75
82
|
const callToolResult: CallToolResult = {
|
|
76
83
|
content: contentItems,
|
|
84
|
+
structuredContent: {
|
|
85
|
+
word: "quotidian",
|
|
86
|
+
},
|
|
77
87
|
};
|
|
78
88
|
|
|
79
89
|
const callToolErrorResult: CallToolResult = {
|
|
@@ -139,6 +139,18 @@ The registry key and `Brand.name` should match. Brand primary colors are CSS-sty
|
|
|
139
139
|
- `VSCODE_COLOR_THEME_KIND`: automatic VS Code theme hint used after the macOS hint.
|
|
140
140
|
- `COLORFGBG`: terminal foreground/background hint used after the macOS and VS Code hints. Rendering defaults to dark when no hint resolves a mode.
|
|
141
141
|
|
|
142
|
+
### Prompts
|
|
143
|
+
|
|
144
|
+
- `POE_NO_PROMPT`: when set to `1` in non-TTY contexts, `confirm`, `select`, and `multiselect` accept their default or initial values instead of throwing an interactive TTY error.
|
|
145
|
+
|
|
146
|
+
### Node 18 Smoke
|
|
147
|
+
|
|
148
|
+
After building the package, verify the prompt entrypoint under Node 18 with:
|
|
149
|
+
|
|
150
|
+
```sh
|
|
151
|
+
nvm exec 18.18 node packages/toolcraft-design/scripts/check-node18.mjs
|
|
152
|
+
```
|
|
153
|
+
|
|
142
154
|
### Output and Color
|
|
143
155
|
|
|
144
156
|
- `OUTPUT_FORMAT`: selects `terminal`, `markdown`, or `json` output for components that use the output-format resolver. Invalid or missing values default to `terminal`.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { CANCEL } from "./interactive/cancel-symbol.js";
|
|
2
|
+
import { type SelectOption } from "./interactive/select.js";
|
|
2
3
|
import { cancel, isCancel } from "./primitives/cancel.js";
|
|
3
4
|
import { intro } from "./primitives/intro.js";
|
|
4
5
|
import { log } from "./primitives/log.js";
|
|
@@ -10,15 +11,24 @@ export { intro, outro, note, spinner };
|
|
|
10
11
|
export declare function introPlain(title: string): void;
|
|
11
12
|
export interface SelectOptions<Value> {
|
|
12
13
|
message: string;
|
|
13
|
-
options: Array<
|
|
14
|
-
value: Value;
|
|
15
|
-
label: string;
|
|
16
|
-
hint?: string;
|
|
17
|
-
}>;
|
|
14
|
+
options: Array<SelectOption<Value>>;
|
|
18
15
|
initialValue?: Value;
|
|
16
|
+
maxItems?: number;
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
input?: NodeJS.ReadableStream;
|
|
19
|
+
output?: NodeJS.WritableStream;
|
|
20
|
+
}
|
|
21
|
+
export declare function select<Value>(opts: SelectOptions<Value>): Promise<Value | typeof CANCEL>;
|
|
22
|
+
export interface MultiselectOptions<Value> {
|
|
23
|
+
message: string;
|
|
24
|
+
options: Array<SelectOption<Value>>;
|
|
25
|
+
initialValues?: Value[];
|
|
26
|
+
required?: boolean;
|
|
27
|
+
maxItems?: number;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
input?: NodeJS.ReadableStream;
|
|
30
|
+
output?: NodeJS.WritableStream;
|
|
19
31
|
}
|
|
20
|
-
export declare function select<Value>(opts: SelectOptions<Value>): Promise<Value | symbol>;
|
|
21
|
-
export type MultiselectOptions<Value> = Parameters<typeof clack.multiselect<Value>>[0];
|
|
22
32
|
/**
|
|
23
33
|
* Prompts the user to select one or more values from a list.
|
|
24
34
|
*
|
|
@@ -35,23 +45,38 @@ export type MultiselectOptions<Value> = Parameters<typeof clack.multiselect<Valu
|
|
|
35
45
|
* // result is Value[]
|
|
36
46
|
* }
|
|
37
47
|
*/
|
|
38
|
-
export declare function multiselect<Value>(opts: MultiselectOptions<Value>): Promise<Value[] |
|
|
39
|
-
export
|
|
40
|
-
|
|
48
|
+
export declare function multiselect<Value>(opts: MultiselectOptions<Value>): Promise<Value[] | typeof CANCEL>;
|
|
49
|
+
export interface TextOptions {
|
|
50
|
+
message: string;
|
|
51
|
+
placeholder?: string;
|
|
52
|
+
defaultValue?: string;
|
|
53
|
+
initialValue?: string;
|
|
54
|
+
validate?: (value: string) => string | Error | undefined;
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
input?: NodeJS.ReadableStream;
|
|
57
|
+
output?: NodeJS.WritableStream;
|
|
58
|
+
}
|
|
59
|
+
export declare function text(opts: TextOptions): Promise<string | typeof CANCEL>;
|
|
41
60
|
export interface ConfirmOptions {
|
|
42
61
|
message: string;
|
|
43
62
|
initialValue?: boolean;
|
|
63
|
+
signal?: AbortSignal;
|
|
64
|
+
input?: NodeJS.ReadableStream;
|
|
65
|
+
output?: NodeJS.WritableStream;
|
|
44
66
|
}
|
|
45
|
-
export declare function confirm(opts: ConfirmOptions): Promise<boolean |
|
|
67
|
+
export declare function confirm(opts: ConfirmOptions): Promise<boolean | typeof CANCEL>;
|
|
46
68
|
export declare class PromptCancelledError extends Error {
|
|
47
69
|
constructor(message?: string);
|
|
48
70
|
}
|
|
49
71
|
export declare function confirmOrCancel(opts: ConfirmOptions): Promise<boolean>;
|
|
50
72
|
export interface PasswordOptions {
|
|
51
73
|
message: string;
|
|
52
|
-
validate?: (value: string) => string | undefined;
|
|
74
|
+
validate?: (value: string) => string | Error | undefined;
|
|
75
|
+
signal?: AbortSignal;
|
|
76
|
+
input?: NodeJS.ReadableStream;
|
|
77
|
+
output?: NodeJS.WritableStream;
|
|
53
78
|
}
|
|
54
|
-
export declare function password(opts: PasswordOptions): Promise<string |
|
|
79
|
+
export declare function password(opts: PasswordOptions): Promise<string | typeof CANCEL>;
|
|
55
80
|
export type SpinnerOptions = {
|
|
56
81
|
start: (message?: string) => void;
|
|
57
82
|
stop: (message?: string, code?: number) => void;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { color } from "../components/color.js";
|
|
2
|
-
import * as clack from "@clack/prompts";
|
|
3
2
|
import { resolveOutputFormat } from "../internal/output-format.js";
|
|
4
3
|
import { stripAnsi } from "../internal/strip-ansi.js";
|
|
4
|
+
import { confirmPrompt } from "./interactive/confirm.js";
|
|
5
|
+
import { multiselectPrompt } from "./interactive/multiselect.js";
|
|
6
|
+
import { passwordPrompt } from "./interactive/password.js";
|
|
7
|
+
import { selectPrompt } from "./interactive/select.js";
|
|
8
|
+
import { textPrompt } from "./interactive/text.js";
|
|
5
9
|
import { cancel, isCancel } from "./primitives/cancel.js";
|
|
6
10
|
import { intro } from "./primitives/intro.js";
|
|
7
11
|
import { log } from "./primitives/log.js";
|
|
@@ -22,7 +26,7 @@ export function introPlain(title) {
|
|
|
22
26
|
process.stdout.write(`${color.gray("┌")} ${title}\n`);
|
|
23
27
|
}
|
|
24
28
|
export async function select(opts) {
|
|
25
|
-
return
|
|
29
|
+
return selectPrompt(opts);
|
|
26
30
|
}
|
|
27
31
|
/**
|
|
28
32
|
* Prompts the user to select one or more values from a list.
|
|
@@ -41,13 +45,13 @@ export async function select(opts) {
|
|
|
41
45
|
* }
|
|
42
46
|
*/
|
|
43
47
|
export async function multiselect(opts) {
|
|
44
|
-
return
|
|
48
|
+
return multiselectPrompt(opts);
|
|
45
49
|
}
|
|
46
50
|
export async function text(opts) {
|
|
47
|
-
return
|
|
51
|
+
return textPrompt(opts);
|
|
48
52
|
}
|
|
49
53
|
export async function confirm(opts) {
|
|
50
|
-
return
|
|
54
|
+
return confirmPrompt(opts);
|
|
51
55
|
}
|
|
52
56
|
export class PromptCancelledError extends Error {
|
|
53
57
|
constructor(message = "Operation cancelled.") {
|
|
@@ -67,7 +71,7 @@ export async function confirmOrCancel(opts) {
|
|
|
67
71
|
return result === true;
|
|
68
72
|
}
|
|
69
73
|
export async function password(opts) {
|
|
70
|
-
return
|
|
74
|
+
return passwordPrompt(opts);
|
|
71
75
|
}
|
|
72
76
|
function formatElapsed(ms) {
|
|
73
77
|
const totalSeconds = Math.floor(ms / 1000);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CANCEL } from "./cancel-symbol.js";
|
|
2
|
+
export interface ConfirmOptions {
|
|
3
|
+
message: string;
|
|
4
|
+
initialValue?: boolean;
|
|
5
|
+
signal?: AbortSignal;
|
|
6
|
+
input?: NodeJS.ReadableStream;
|
|
7
|
+
output?: NodeJS.WritableStream;
|
|
8
|
+
}
|
|
9
|
+
export declare function confirmPrompt(opts: ConfirmOptions): Promise<boolean | typeof CANCEL>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { color } from "../../components/color.js";
|
|
2
|
+
import { GLYPHS, symbol, symbolBar } from "./glyphs.js";
|
|
3
|
+
import { Prompt } from "./core.js";
|
|
4
|
+
class ConfirmPrompt extends Prompt {
|
|
5
|
+
constructor(opts) {
|
|
6
|
+
super({
|
|
7
|
+
...opts,
|
|
8
|
+
initialValue: opts.initialValue ?? true,
|
|
9
|
+
render: (prompt) => renderConfirmPrompt(prompt, opts)
|
|
10
|
+
}, false);
|
|
11
|
+
this.on("confirm", (value) => {
|
|
12
|
+
this.setValue(value);
|
|
13
|
+
this.state = "submit";
|
|
14
|
+
this.emit("finalize");
|
|
15
|
+
this.render();
|
|
16
|
+
this.close();
|
|
17
|
+
});
|
|
18
|
+
this.on("cursor", (action) => {
|
|
19
|
+
if (action === "up" || action === "down" || action === "left" || action === "right") {
|
|
20
|
+
this.setValue(!this.value);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
promptNonTty() {
|
|
25
|
+
if (process.env.POE_NO_PROMPT === "1") {
|
|
26
|
+
return Promise.resolve(this.value ?? true);
|
|
27
|
+
}
|
|
28
|
+
return super.promptNonTty();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function choices(value) {
|
|
32
|
+
const yes = value ? `${color.green(GLYPHS.radioActive)} ${color.bold("Yes")}` : `${color.dim(GLYPHS.radioInactive)} ${color.dim("Yes")}`;
|
|
33
|
+
const no = value ? `${color.dim(GLYPHS.radioInactive)} ${color.dim("No")}` : `${color.green(GLYPHS.radioActive)} ${color.bold("No")}`;
|
|
34
|
+
return `${yes} ${color.dim("/")} ${no}`;
|
|
35
|
+
}
|
|
36
|
+
function renderConfirmPrompt(prompt, opts) {
|
|
37
|
+
if (prompt.state === "submit") {
|
|
38
|
+
return `${color.gray(GLYPHS.barStart)} ${symbol(prompt.state)} ${opts.message}\n${color.gray(GLYPHS.bar)} ${color.dim(prompt.value ? "Yes" : "No")}\n${color.green(GLYPHS.barEnd)}`;
|
|
39
|
+
}
|
|
40
|
+
if (prompt.state === "cancel") {
|
|
41
|
+
return `${color.gray(GLYPHS.barStart)} ${symbol(prompt.state)} ${opts.message}\n${color.gray(GLYPHS.bar)} ${color.dim.strikethrough(prompt.value ? "Yes" : "No")}\n${color.red(GLYPHS.barEnd)}`;
|
|
42
|
+
}
|
|
43
|
+
return `${color.gray(GLYPHS.barStart)} ${symbol(prompt.state)} ${opts.message}\n${symbolBar(prompt.state)} ${choices(prompt.value)}\n${color.cyan(GLYPHS.barEnd)}`;
|
|
44
|
+
}
|
|
45
|
+
export function confirmPrompt(opts) {
|
|
46
|
+
return new ConfirmPrompt(opts).prompt();
|
|
47
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { CANCEL } from "./cancel-symbol.js";
|
|
3
|
+
export type PromptStateName = "initial" | "active" | "submit" | "cancel" | "error";
|
|
4
|
+
export interface PromptState<Value> {
|
|
5
|
+
state: PromptStateName;
|
|
6
|
+
value: Value | undefined;
|
|
7
|
+
error: string;
|
|
8
|
+
cursor: number;
|
|
9
|
+
userInput: string;
|
|
10
|
+
}
|
|
11
|
+
export interface PromptOptions<Value> {
|
|
12
|
+
render: (state: Prompt<Value>) => string;
|
|
13
|
+
initialValue?: Value;
|
|
14
|
+
initialUserInput?: string;
|
|
15
|
+
validate?: (value: Value | undefined) => string | Error | undefined;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
input?: NodeJS.ReadableStream;
|
|
18
|
+
output?: NodeJS.WritableStream;
|
|
19
|
+
}
|
|
20
|
+
type InputStream = NodeJS.ReadableStream & {
|
|
21
|
+
isTTY?: boolean;
|
|
22
|
+
setRawMode?: (enabled: boolean) => void;
|
|
23
|
+
unpipe?: () => void;
|
|
24
|
+
};
|
|
25
|
+
export declare class Prompt<Value> extends EventEmitter {
|
|
26
|
+
state: PromptStateName;
|
|
27
|
+
value: Value | undefined;
|
|
28
|
+
error: string;
|
|
29
|
+
userInput: string;
|
|
30
|
+
protected _cursor: number;
|
|
31
|
+
protected input: InputStream;
|
|
32
|
+
protected output: NodeJS.WritableStream;
|
|
33
|
+
private readonly renderFrame;
|
|
34
|
+
private readonly validate?;
|
|
35
|
+
private readonly signal?;
|
|
36
|
+
private readonly trackValue;
|
|
37
|
+
private previousFrame;
|
|
38
|
+
private readlineInterface?;
|
|
39
|
+
private abortListener?;
|
|
40
|
+
private closed;
|
|
41
|
+
constructor(opts: PromptOptions<Value>, trackValue?: boolean);
|
|
42
|
+
get cursor(): number;
|
|
43
|
+
prompt(): Promise<Value | typeof CANCEL>;
|
|
44
|
+
protected promptNonTty(): Promise<Value | typeof CANCEL>;
|
|
45
|
+
protected readNonTtyLine(): Promise<string>;
|
|
46
|
+
protected setValue(value: Value | undefined): void;
|
|
47
|
+
protected setError(message: string): void;
|
|
48
|
+
protected setUserInput(value: string): void;
|
|
49
|
+
protected clearUserInput(): void;
|
|
50
|
+
private readonly onKeypress;
|
|
51
|
+
private updateTrackedInput;
|
|
52
|
+
protected readonly render: () => void;
|
|
53
|
+
protected close(): void;
|
|
54
|
+
}
|
|
55
|
+
export {};
|