burgee 0.0.0 → 0.3.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/README.md +28 -1
- package/dist/agent.d.ts +19 -0
- package/dist/agent.js +25 -0
- package/dist/brand.d.ts +186 -0
- package/dist/brand.js +232 -0
- package/dist/cli.d.ts +62 -0
- package/dist/cli.js +121 -0
- package/dist/commander-argument.d.ts +22 -0
- package/dist/commander-argument.js +72 -0
- package/dist/commander-command.d.ts +355 -0
- package/dist/commander-command.js +1621 -0
- package/dist/commander-error.d.ts +10 -0
- package/dist/commander-error.js +20 -0
- package/dist/commander-help.d.ts +67 -0
- package/dist/commander-help.js +319 -0
- package/dist/commander-option.d.ts +58 -0
- package/dist/commander-option.js +164 -0
- package/dist/commander-suggest.d.ts +2 -0
- package/dist/commander-suggest.js +59 -0
- package/dist/commander.d.ts +18 -0
- package/dist/commander.js +12 -0
- package/dist/completions.d.ts +39 -0
- package/dist/completions.js +224 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.js +98 -0
- package/dist/contrast.d.ts +70 -0
- package/dist/contrast.js +93 -0
- package/dist/dev.d.ts +47 -0
- package/dist/dev.js +132 -0
- package/dist/execute.d.ts +118 -0
- package/dist/execute.js +469 -0
- package/dist/exit-code.d.ts +18 -0
- package/dist/exit-code.js +12 -0
- package/dist/help.d.ts +34 -0
- package/dist/help.js +187 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.js +9 -2
- package/dist/manifest.d.ts +207 -0
- package/dist/manifest.js +66 -0
- package/dist/mcp.d.ts +52 -0
- package/dist/mcp.js +124 -0
- package/dist/names.d.ts +5 -0
- package/dist/names.js +6 -0
- package/dist/pkg.d.ts +5 -0
- package/dist/pkg.js +21 -0
- package/dist/precedence.d.ts +55 -0
- package/dist/precedence.js +100 -0
- package/dist/runtime.d.ts +39 -0
- package/dist/runtime.js +24 -0
- package/dist/schema.d.ts +79 -0
- package/dist/schema.js +116 -0
- package/dist/testing-helpers.d.ts +79 -0
- package/dist/testing-helpers.js +145 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.js +3 -0
- package/dist/validate.d.ts +27 -0
- package/dist/validate.js +133 -0
- package/dist/yargs-burgee.d.ts +50 -0
- package/dist/yargs-burgee.js +104 -0
- package/dist/yargs-cliui.d.ts +56 -0
- package/dist/yargs-cliui.js +421 -0
- package/dist/yargs-command.d.ts +82 -0
- package/dist/yargs-command.js +414 -0
- package/dist/yargs-completion.d.ts +41 -0
- package/dist/yargs-completion.js +271 -0
- package/dist/yargs-factory.d.ts +193 -0
- package/dist/yargs-factory.js +1606 -0
- package/dist/yargs-helpers.d.ts +6 -0
- package/dist/yargs-helpers.js +2 -0
- package/dist/yargs-middleware.d.ts +32 -0
- package/dist/yargs-middleware.js +81 -0
- package/dist/yargs-parser.d.ts +41 -0
- package/dist/yargs-parser.js +929 -0
- package/dist/yargs-shim.d.ts +54 -0
- package/dist/yargs-shim.js +84 -0
- package/dist/yargs-usage.d.ts +42 -0
- package/dist/yargs-usage.js +479 -0
- package/dist/yargs-utils.d.ts +33 -0
- package/dist/yargs-utils.js +209 -0
- package/dist/yargs-validation.d.ts +26 -0
- package/dist/yargs-validation.js +261 -0
- package/dist/yargs-y18n.d.ts +21 -0
- package/dist/yargs-y18n.js +117 -0
- package/dist/yargs.d.ts +6 -0
- package/dist/yargs.js +8 -0
- package/locales/be.json +46 -0
- package/locales/cs.json +51 -0
- package/locales/de.json +46 -0
- package/locales/en.json +55 -0
- package/locales/es.json +46 -0
- package/locales/fi.json +49 -0
- package/locales/fr.json +53 -0
- package/locales/he.json +55 -0
- package/locales/hi.json +49 -0
- package/locales/hu.json +46 -0
- package/locales/id.json +50 -0
- package/locales/it.json +46 -0
- package/locales/ja.json +51 -0
- package/locales/ka.json +55 -0
- package/locales/ko.json +49 -0
- package/locales/nb.json +44 -0
- package/locales/nl.json +49 -0
- package/locales/nn.json +44 -0
- package/locales/pirate.json +13 -0
- package/locales/pl.json +49 -0
- package/locales/pt.json +45 -0
- package/locales/pt_BR.json +48 -0
- package/locales/ru.json +51 -0
- package/locales/th.json +46 -0
- package/locales/tr.json +48 -0
- package/locales/uk_UA.json +51 -0
- package/locales/uz.json +52 -0
- package/locales/zh_CN.json +48 -0
- package/locales/zh_TW.json +51 -0
- package/package.json +62 -9
- package/dist/index.js.map +0 -1
package/dist/dev.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Manifest } from './manifest.js';
|
|
2
|
+
import { type Invoke } from './mcp.js';
|
|
3
|
+
export interface Writer {
|
|
4
|
+
write: (s: string) => unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface DevOptions {
|
|
7
|
+
/** The module that exports the program: `program` (or `default`) as a burgee manifest, a commander `Command` or a yargs instance. */
|
|
8
|
+
entry: string;
|
|
9
|
+
/** The MCP channel. */
|
|
10
|
+
input: NodeJS.ReadableStream;
|
|
11
|
+
output: Writer;
|
|
12
|
+
/** Where the reload report goes: never stdout, which carries MCP. */
|
|
13
|
+
log: Writer;
|
|
14
|
+
/** Off for tests that drive `reload()` themselves. */
|
|
15
|
+
watch?: boolean;
|
|
16
|
+
/** Files changed within this window coalesce into one reload. */
|
|
17
|
+
debounceMs?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface Loaded {
|
|
20
|
+
manifest: Manifest;
|
|
21
|
+
invoke: Invoke;
|
|
22
|
+
kind: 'burgee' | 'commander' | 'yargs';
|
|
23
|
+
/** Milliseconds from the trigger to the manifest being served (W6). */
|
|
24
|
+
ms: number;
|
|
25
|
+
}
|
|
26
|
+
export interface DevHandle {
|
|
27
|
+
ready: Promise<Loaded>;
|
|
28
|
+
/** Re-import the entry, print the diff and the help, swap the served manifest. */
|
|
29
|
+
reload: () => Promise<Loaded>;
|
|
30
|
+
/** Settles when the MCP input closes. */
|
|
31
|
+
done: Promise<void>;
|
|
32
|
+
close: () => void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Import the entry as a fresh module graph. The query is what discards the previous
|
|
36
|
+
* graph: the same URL would hand back the cached module and its stale handlers.
|
|
37
|
+
*/
|
|
38
|
+
export declare function load(entry: string, generation: number): Promise<Loaded>;
|
|
39
|
+
/** What changed between two manifests, by command path: added, removed, or a different schema. */
|
|
40
|
+
export declare function diffManifests(before: Manifest | undefined, after: Manifest): {
|
|
41
|
+
added: string[];
|
|
42
|
+
removed: string[];
|
|
43
|
+
changed: string[];
|
|
44
|
+
};
|
|
45
|
+
/** The reload report: one save, every surface (W3). */
|
|
46
|
+
export declare function report(before: Manifest | undefined, loaded: Loaded): string;
|
|
47
|
+
export declare function dev(opts: DevOptions): DevHandle;
|
package/dist/dev.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { watch } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { execute } from './execute.js';
|
|
5
|
+
import { renderHelp } from './help.js';
|
|
6
|
+
import { Manifest } from './manifest.js';
|
|
7
|
+
import { startMcp, toolsOf } from './mcp.js';
|
|
8
|
+
import { commandSchemaOf } from './schema.js';
|
|
9
|
+
const DEFAULT_DEBOUNCE_MS = 50;
|
|
10
|
+
const SOURCE = /\.(m?[jt]s|c[jt]s|json)$/;
|
|
11
|
+
const isObject = (x) => x !== null && x !== undefined && typeof x === 'object' && !Array.isArray(x);
|
|
12
|
+
function isManifest(x) {
|
|
13
|
+
return x instanceof Manifest || (isObject(x) && Array.isArray(x['commands']) && Array.isArray(x['rootPath']));
|
|
14
|
+
}
|
|
15
|
+
function isYargs(x) {
|
|
16
|
+
return isObject(x) && typeof x['burgee'] === 'function' && isObject(x['manifest']);
|
|
17
|
+
}
|
|
18
|
+
function isCommander(x) {
|
|
19
|
+
return isObject(x) && typeof x['parseAsync'] === 'function' && isObject(x['manifest']);
|
|
20
|
+
}
|
|
21
|
+
function invokeOn(program, kind, entry) {
|
|
22
|
+
return async (argv) => {
|
|
23
|
+
const out = [];
|
|
24
|
+
const err = [];
|
|
25
|
+
let code = 0;
|
|
26
|
+
const seam = { stdout: { write: (s) => out.push(s) }, stderr: { write: (s) => err.push(s) }, exit: (c) => void (code = c) };
|
|
27
|
+
if (kind === 'burgee')
|
|
28
|
+
await execute(program, { argv, from: 'user', entry, ...seam });
|
|
29
|
+
else if (kind === 'yargs')
|
|
30
|
+
await program.burgee(seam).parseAsync(argv);
|
|
31
|
+
else
|
|
32
|
+
await program.parseAsync(argv, { from: 'user', ...seam });
|
|
33
|
+
return { stdout: out.join(''), stderr: err.join(''), code };
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export async function load(entry, generation) {
|
|
37
|
+
const started = performance.now();
|
|
38
|
+
const url = pathToFileURL(resolve(entry));
|
|
39
|
+
url.searchParams.set('burgee-dev', String(generation));
|
|
40
|
+
const mod = (await import(url.href));
|
|
41
|
+
const exported = mod['program'] ?? mod['default'];
|
|
42
|
+
if (isManifest(exported))
|
|
43
|
+
return { manifest: exported, invoke: invokeOn(exported, 'burgee', entry), kind: 'burgee', ms: performance.now() - started };
|
|
44
|
+
if (isYargs(exported))
|
|
45
|
+
return { manifest: exported.manifest, invoke: invokeOn(exported, 'yargs', entry), kind: 'yargs', ms: performance.now() - started };
|
|
46
|
+
if (isCommander(exported))
|
|
47
|
+
return { manifest: exported.manifest, invoke: invokeOn(exported, 'commander', entry), kind: 'commander', ms: performance.now() - started };
|
|
48
|
+
throw new Error(`${entry} exports no program: export a burgee manifest, a commander Command or a yargs instance as \`program\` or default`);
|
|
49
|
+
}
|
|
50
|
+
const schemasByPath = (m) => new Map(m.commands.map((c) => [c.path.join(' '), JSON.stringify(commandSchemaOf(c, m.rootPath))]));
|
|
51
|
+
export function diffManifests(before, after) {
|
|
52
|
+
const was = before === undefined ? new Map() : schemasByPath(before);
|
|
53
|
+
const now = schemasByPath(after);
|
|
54
|
+
return {
|
|
55
|
+
added: [...now.keys()].filter((k) => !was.has(k)),
|
|
56
|
+
removed: [...was.keys()].filter((k) => !now.has(k)),
|
|
57
|
+
changed: [...now.keys()].filter((k) => was.has(k) && was.get(k) !== now.get(k)),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function report(before, loaded) {
|
|
61
|
+
const { manifest } = loaded;
|
|
62
|
+
const diff = diffManifests(before, manifest);
|
|
63
|
+
const lines = [];
|
|
64
|
+
lines.push(`${before === undefined ? 'loaded' : 'reloaded'} ${manifest.rootPath.join(' ')} (${loaded.kind}) in ${loaded.ms.toFixed(0)} ms — ${manifest.commands.length} commands, ${toolsOf(manifest).length} MCP tools`);
|
|
65
|
+
for (const p of diff.added)
|
|
66
|
+
lines.push(` + ${p}`);
|
|
67
|
+
for (const p of diff.removed)
|
|
68
|
+
lines.push(` - ${p}`);
|
|
69
|
+
for (const p of diff.changed)
|
|
70
|
+
lines.push(` ~ ${p}`);
|
|
71
|
+
const root = manifest.find(manifest.rootPath);
|
|
72
|
+
if (root !== undefined)
|
|
73
|
+
lines.push('', renderHelp(manifest, root).trimEnd());
|
|
74
|
+
return `${lines.join('\n')}\n`;
|
|
75
|
+
}
|
|
76
|
+
export function dev(opts) {
|
|
77
|
+
let generation = 0;
|
|
78
|
+
let current;
|
|
79
|
+
let server;
|
|
80
|
+
let watcher;
|
|
81
|
+
let timer;
|
|
82
|
+
let chain = Promise.resolve();
|
|
83
|
+
const entry = resolve(opts.entry);
|
|
84
|
+
const reloadNow = async () => {
|
|
85
|
+
generation += 1;
|
|
86
|
+
const loaded = await load(entry, generation);
|
|
87
|
+
opts.log.write(report(current, loaded));
|
|
88
|
+
current = loaded.manifest;
|
|
89
|
+
if (server === undefined)
|
|
90
|
+
server = startMcp(loaded.manifest, { input: opts.input, output: opts.output, invoke: loaded.invoke });
|
|
91
|
+
else
|
|
92
|
+
server.swap(loaded.manifest, loaded.invoke);
|
|
93
|
+
return loaded;
|
|
94
|
+
};
|
|
95
|
+
const reload = async () => {
|
|
96
|
+
await chain;
|
|
97
|
+
const next = reloadNow();
|
|
98
|
+
chain = next.catch((err) => {
|
|
99
|
+
opts.log.write(`reload failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
100
|
+
});
|
|
101
|
+
return await next;
|
|
102
|
+
};
|
|
103
|
+
const ready = reload();
|
|
104
|
+
if (opts.watch !== false) {
|
|
105
|
+
watcher = watch(dirname(entry), { recursive: true }, (_event, filename) => {
|
|
106
|
+
const name = filename === null ? '' : String(filename);
|
|
107
|
+
if (name !== '' && (!SOURCE.test(name) || name.includes('node_modules')))
|
|
108
|
+
return;
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
timer = setTimeout(() => void reload().catch(() => undefined), opts.debounceMs ?? DEFAULT_DEBOUNCE_MS);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
const untilInputCloses = async () => {
|
|
114
|
+
try {
|
|
115
|
+
await ready;
|
|
116
|
+
await server.done;
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
watcher?.close();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const done = untilInputCloses();
|
|
123
|
+
return {
|
|
124
|
+
ready,
|
|
125
|
+
reload,
|
|
126
|
+
done,
|
|
127
|
+
close: () => {
|
|
128
|
+
clearTimeout(timer);
|
|
129
|
+
watcher?.close();
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { type ArgumentSpec, type CommandNode, type Effects, type Example, type LazyModule, Manifest, type OptionSpec, type Relation, type RunContext } from './manifest.js';
|
|
2
|
+
export interface CommandContext<O> extends Omit<RunContext, 'options'> {
|
|
3
|
+
options: O;
|
|
4
|
+
}
|
|
5
|
+
type Scalar<S extends OptionSpec> = S['type'] extends 'number' ? number : S['type'] extends 'boolean' ? boolean : S extends {
|
|
6
|
+
choices: readonly (infer C)[];
|
|
7
|
+
} ? C : string;
|
|
8
|
+
type Many<S extends OptionSpec, V> = S extends {
|
|
9
|
+
multiple: true;
|
|
10
|
+
} ? V[] : V;
|
|
11
|
+
type Present<S extends OptionSpec> = S extends {
|
|
12
|
+
required: true;
|
|
13
|
+
} ? true : S extends {
|
|
14
|
+
default: unknown;
|
|
15
|
+
} ? true : false;
|
|
16
|
+
/** The handler's `options`, derived from the declaration (S1): `choices` become a union, `multiple` an array, `number` a number. */
|
|
17
|
+
export type InferOptions<S extends Record<string, OptionSpec>> = {
|
|
18
|
+
[K in keyof S]: Present<S[K]> extends true ? Many<S[K], Scalar<S[K]>> : Many<S[K], Scalar<S[K]>> | undefined;
|
|
19
|
+
};
|
|
20
|
+
export type OptionSpecs = Record<string, OptionSpec>;
|
|
21
|
+
export type AnyCommand = Command<any>;
|
|
22
|
+
export interface Command<S extends OptionSpecs = OptionSpecs> {
|
|
23
|
+
name: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
/** Shown in command lists instead of the description. */
|
|
26
|
+
summary?: string;
|
|
27
|
+
/** Declared once (S1); the handler's `options` type is derived from it. */
|
|
28
|
+
options?: S;
|
|
29
|
+
arguments?: ArgumentSpec[];
|
|
30
|
+
examples?: Example[];
|
|
31
|
+
/** Heading this command is listed under in its parent's help. */
|
|
32
|
+
group?: string;
|
|
33
|
+
epilogue?: string;
|
|
34
|
+
hidden?: boolean;
|
|
35
|
+
deprecated?: boolean | string;
|
|
36
|
+
/** What running it does to the world (N6). Declaring it is what exposes the command as an MCP tool (N2). */
|
|
37
|
+
effects?: Effects;
|
|
38
|
+
/** Relationships between options, validated before choices and the handler (S2, S6). */
|
|
39
|
+
relations?: readonly Relation[];
|
|
40
|
+
/** Absent on a group that only holds subcommands. `NoInfer`: the spec fixes S, the handler only reads it. */
|
|
41
|
+
run?: (ctx: CommandContext<InferOptions<NoInfer<S>>>) => unknown;
|
|
42
|
+
/** The handler's module, imported on dispatch only (M2); everything else about the command is declared here. */
|
|
43
|
+
load?: () => Promise<LazyModule>;
|
|
44
|
+
commands?: AnyCommand[];
|
|
45
|
+
}
|
|
46
|
+
export interface Program {
|
|
47
|
+
name: string;
|
|
48
|
+
version?: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
/** Options read `PREFIX_OPTION_NAME` from the environment unless they name their own variable (V2). */
|
|
51
|
+
envPrefix?: string;
|
|
52
|
+
/** Characters of `--schema` output above which it is summarised (N13); 48,000 by default. */
|
|
53
|
+
schemaBudget?: number;
|
|
54
|
+
/**
|
|
55
|
+
* Opt into config discovery (V6): `--config <path>` > `NAME_CONFIG` > `./name.config.{json,mjs,js,cjs}`
|
|
56
|
+
* > `package.json#name` > the user config directory; `true` uses the program's name.
|
|
57
|
+
*/
|
|
58
|
+
config?: boolean | {
|
|
59
|
+
name: string;
|
|
60
|
+
};
|
|
61
|
+
commands: AnyCommand[];
|
|
62
|
+
}
|
|
63
|
+
export declare function defineCommand<const S extends OptionSpecs = OptionSpecs>(command: Command<S>): Command<S>;
|
|
64
|
+
/**
|
|
65
|
+
* Options declared once and spread into each command that takes them (M4): never global,
|
|
66
|
+
* so `--schema` stays a tree and each command's help lists them as its own, and the
|
|
67
|
+
* handler's `options` type carries them like any other. Every copy is tagged
|
|
68
|
+
* `sharedFrom` with the set's name, so the schema says where it came from.
|
|
69
|
+
*/
|
|
70
|
+
export declare function sharedOptions<const T extends OptionSpecs>(name: string, specs: T): T;
|
|
71
|
+
/** A native multi-command program. The manifest it builds is the same one the façades fill. */
|
|
72
|
+
export declare function defineProgram(program: Program): Manifest;
|
|
73
|
+
export interface RunOptions {
|
|
74
|
+
argv?: string[];
|
|
75
|
+
/** Read only by `--mcp`, which serves JSON-RPC over it. */
|
|
76
|
+
stdin?: NodeJS.ReadableStream;
|
|
77
|
+
/** The environment env-bound options read from. Injected by the harness; the process's own otherwise. */
|
|
78
|
+
env?: Record<string, string | undefined>;
|
|
79
|
+
/** `columns` is read when present, so help wraps to the terminal (H3); `isTTY` feeds agent detection (N12). */
|
|
80
|
+
stdout?: {
|
|
81
|
+
write: (s: string) => unknown;
|
|
82
|
+
columns?: number;
|
|
83
|
+
isTTY?: boolean;
|
|
84
|
+
};
|
|
85
|
+
stderr?: {
|
|
86
|
+
write: (s: string) => unknown;
|
|
87
|
+
};
|
|
88
|
+
/** Receives the E1 code. The default calls process.exit; an injected one may simply record it. */
|
|
89
|
+
exit?: (code: number) => void;
|
|
90
|
+
/** Where config discovery starts; the process's own otherwise. */
|
|
91
|
+
cwd?: string;
|
|
92
|
+
/** The entry file, whose nearest package.json owns the program's version (V4); `process.argv[1]` otherwise. */
|
|
93
|
+
entry?: string;
|
|
94
|
+
}
|
|
95
|
+
/** The part of argv the parser will read as options: everything before `--`. */
|
|
96
|
+
export declare function beforeTerminator(argv: readonly string[]): readonly string[];
|
|
97
|
+
export declare function execute(manifest: Manifest, opts?: RunOptions & {
|
|
98
|
+
root?: string[];
|
|
99
|
+
from?: 'node' | 'user';
|
|
100
|
+
}): Promise<void>;
|
|
101
|
+
/** M6: which command argv names, or null — the same longest-prefix match `execute` uses. */
|
|
102
|
+
export declare function resolveCommand(manifest: Manifest, argv: readonly string[]): CommandNode | null;
|
|
103
|
+
export interface RunResult {
|
|
104
|
+
code: number;
|
|
105
|
+
stdout: string;
|
|
106
|
+
stderr: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* M6: run a command programmatically — the harness's own entry, public. The streams are
|
|
110
|
+
* captured, the exit recorded; env, cwd and the entry can be injected like `execute`'s.
|
|
111
|
+
*/
|
|
112
|
+
export declare function runCommand(manifest: Manifest, argv: readonly string[], opts?: Pick<RunOptions, 'env' | 'cwd' | 'entry' | 'stdin'>): Promise<RunResult>;
|
|
113
|
+
/**
|
|
114
|
+
* The one-file entry: a single command, or a program from `defineProgram`. Both go
|
|
115
|
+
* through `execute`, so there is exactly one code path from argv to exit.
|
|
116
|
+
*/
|
|
117
|
+
export declare function run<S extends OptionSpecs>(target: Command<S> | Manifest, opts?: RunOptions): Promise<void>;
|
|
118
|
+
export {};
|