burgee 0.6.1 → 0.7.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.
@@ -1,4 +1,5 @@
1
1
  import { strip, width, wrap } from "linegauge";
2
+ import { host } from "../runtime.js";
2
3
  /**
3
4
  * cliui 9 — the column layout yargs' usage renders through — with the wrap-ansi it depends
4
5
  * on, ported for `burgee/yargs`. Width and escape-stripping come from linegauge. The wrapping
@@ -141,7 +142,7 @@ export class UI {
141
142
  if (r === 0 && lines.length > 0)
142
143
  str = this.renderInline(str, lines.at(-1));
143
144
  });
144
- lines.push({ text: str.replace(/ +$/, ""), span: row.span });
145
+ lines.push({ text: trimTrailingSpaces(str), span: row.span });
145
146
  });
146
147
  return lines;
147
148
  }
@@ -221,6 +222,27 @@ export class UI {
221
222
  return widths.map((w, i) => w === undefined ? Math.max(unsetWidth, minWidth(row[i])) : w);
222
223
  }
223
224
  }
225
+ /*
226
+ * `str.replace(/ +$/, "")` was the upstream spelling, and it is the same quadratic shape
227
+ * `measurePadding` had: the start is unanchored, so the engine retries the match at every
228
+ * position in the run of spaces and each attempt walks to the end before failing on the
229
+ * character that is not the end. A row built from a cell of 50,000 spaces then an `x` is
230
+ * 100,001 characters of which the first 50,000 are the left padding, and trimming it cost
231
+ * 1,049 ms of `toString()`'s 1,223 ms. Doubling the cell quadrupled it.
232
+ *
233
+ * `trimEnd()` is linear but not the same function — it also removes tabs, newlines and the
234
+ * rest of `\s`. A trailing tab does reach here: with `wrap: false`, `rasterize` only splits
235
+ * the cell on newlines, so nothing expands the tab and nothing routes the string through
236
+ * `applyLayoutDSL` (that check is behind `this.wrap`). `cliui({ wrap: false }).div('a\t')`
237
+ * renders `'a\t'` today and would render `'a'` under `trimEnd`, and the yargs usage tests
238
+ * compare whole help screens. This removes exactly U+0020, exactly as the regex did.
239
+ */
240
+ function trimTrailingSpaces(str) {
241
+ let end = str.length;
242
+ while (end > 0 && str[end - 1] === " ")
243
+ end--;
244
+ return end === str.length ? str : str.slice(0, end);
245
+ }
224
246
  function addBorder(col, ts, style) {
225
247
  if (col.border) {
226
248
  if (/[.']-+[.']/.test(ts))
@@ -239,9 +261,9 @@ function minWidth(col) {
239
261
  return min;
240
262
  }
241
263
  function getWindowWidth() {
242
- if (typeof process === "object" && process.stdout && process.stdout.columns)
243
- return process.stdout.columns;
244
- return 80;
264
+ // `host.columns` carries the upstream's guard on the process global itself, so a bundle
265
+ // that has no process at all still falls back to 80 rather than throwing.
266
+ return host.columns || 80;
245
267
  }
246
268
  function alignRight(str, width) {
247
269
  str = str.trim();
@@ -5,7 +5,7 @@
5
5
  * `getInternalMethods()` seam are the upstream's — that is what makes a user's
6
6
  * existing program run unchanged (J2).
7
7
  */
8
- import { type Effects, Manifest, type Plugin } from '../manifest.js';
8
+ import { type DeclaredEffects, Manifest, type Plugin } from '../manifest.js';
9
9
  import { type CommandInstance } from './command.js';
10
10
  import { type CompletionFunction } from './completion.js';
11
11
  import { type Middleware } from './middleware.js';
@@ -179,7 +179,7 @@ export declare class YargsInstance {
179
179
  */
180
180
  get manifest(): Manifest;
181
181
  /** burgee: declare what the command does to the world (N6); what exposes it as an MCP tool (N2). */
182
- effects(value: Effects): this;
182
+ effects(value: DeclaredEffects): this;
183
183
  /** Additive: plugins yargs never had. `preRun`/`postRun` fire around every handler. */
184
184
  use(plugin: Plugin): this;
185
185
  /**
@@ -9,7 +9,7 @@ var _a;
9
9
  import { ExitCode } from '../exit-code.js';
10
10
  import { Manifest } from '../manifest.js';
11
11
  import { serveMcp } from '../mcp.js';
12
- import { schemaOf } from '../schema.js';
12
+ import { machineJson, schemaOf } from '../schema.js';
13
13
  import { tokenizeArgString } from '../yargs-parser.js';
14
14
  import { projectManifest, render } from './burgee.js';
15
15
  import { command as Command, isCommandBuilderCallback } from './command.js';
@@ -1315,7 +1315,12 @@ export class YargsInstance {
1315
1315
  });
1316
1316
  }
1317
1317
  if (head.includes('--schema') && !this.#declares('schema')) {
1318
- this.#logger.log(JSON.stringify(schemaOf(this.manifest), null, 2));
1318
+ // R1, through the same seam the engine and the commander façade use. Hand-rolling
1319
+ // `JSON.stringify(…, null, 2)` here made this façade the one front-end that could not
1320
+ // see `--format=json-pretty`, and emitted a different document from the other two for
1321
+ // the same CLI. `--schema` is burgee's surface, not yargs', so it answers to burgee's
1322
+ // byte discipline.
1323
+ this.#logger.log(machineJson(schemaOf(this.manifest), head));
1319
1324
  this.exit(0);
1320
1325
  return true;
1321
1326
  }
@@ -9,6 +9,7 @@ import { createRequire } from 'node:module';
9
9
  import { basename, dirname, extname, join, relative, resolve } from 'node:path';
10
10
  import { fileURLToPath } from 'node:url';
11
11
  import { inspect } from 'node:util';
12
+ import { host } from '../runtime.js';
12
13
  import { Parser } from '../yargs-parser.js';
13
14
  import { cliui, stringWidth } from './cliui.js';
14
15
  import { getProcessArgvBin } from './utils.js';
@@ -71,24 +72,30 @@ export const shim = {
71
72
  assert: { notStrictEqual, strictEqual },
72
73
  cliui,
73
74
  findUp,
74
- getEnv: (key) => process.env[key],
75
+ getEnv: (key) => host.env[key],
75
76
  inspect,
76
77
  getProcessArgvBin,
77
- mainFilename: mainFilename || process.cwd(),
78
+ mainFilename: mainFilename || host.cwd(),
78
79
  Parser,
79
80
  path: { basename, dirname, extname, relative, resolve, join },
80
81
  process: {
81
- argv: () => process.argv,
82
- cwd: process.cwd,
83
- emitWarning: (warning, type) => process.emitWarning(warning, type),
84
- execPath: () => process.execPath,
82
+ argv: () => host.argv,
83
+ cwd: () => host.cwd(),
84
+ emitWarning: (warning, type) => {
85
+ host.emitWarning(warning, type);
86
+ },
87
+ execPath: () => host.execPath,
85
88
  exit: (code) => {
86
- process.exit(code);
89
+ host.exit(code);
90
+ },
91
+ nextTick: (fn, ...args) => {
92
+ host.nextTick(fn, ...args);
87
93
  },
88
- nextTick: process.nextTick,
89
- stdColumns: typeof process.stdout.columns !== 'undefined' ? process.stdout.columns : null,
90
- stdin: () => process.stdin,
91
- stdout: () => process.stdout,
94
+ // Captured, as it was before the seam: `stdColumns` is a value in `PlatformShim`, not
95
+ // a thunk, so yargs reads whatever this object was built with. Unchanged on purpose.
96
+ stdColumns: typeof host.stdout.columns !== 'undefined' ? host.stdout.columns : null,
97
+ stdin: () => host.stdin,
98
+ stdout: () => host.stdout,
92
99
  },
93
100
  readFileSync,
94
101
  readdirSync,
@@ -7,6 +7,7 @@
7
7
  import { readFileSync } from 'node:fs';
8
8
  import { createRequire } from 'node:module';
9
9
  import { dirname, resolve } from 'node:path';
10
+ import { host } from '../runtime.js';
10
11
  export class YError extends Error {
11
12
  constructor(msg) {
12
13
  super(msg || 'yargs error');
@@ -139,7 +140,7 @@ export function maybeAsyncResult(getResult, resultHandler, errorHandler = (err)
139
140
  export function setBlocking(blocking) {
140
141
  if (typeof process === 'undefined')
141
142
  return;
142
- [process.stdout, process.stderr].forEach((_stream) => {
143
+ [host.stdout, host.stderr].forEach((_stream) => {
143
144
  const stream = _stream;
144
145
  if (stream._handle && stream.isTTY && typeof stream._handle.setBlocking === 'function')
145
146
  stream._handle.setBlocking(blocking);
@@ -151,16 +152,16 @@ function getProcessArgvBinIndex() {
151
152
  return 1;
152
153
  }
153
154
  function isBundledElectronApp() {
154
- return isElectronApp() && !process.defaultApp;
155
+ return isElectronApp() && !host.defaultApp;
155
156
  }
156
157
  function isElectronApp() {
157
- return !!process.versions.electron;
158
+ return !!host.versions['electron'];
158
159
  }
159
160
  export function hideBin(argv) {
160
161
  return argv.slice(getProcessArgvBinIndex() + 1);
161
162
  }
162
163
  export function getProcessArgvBin() {
163
- return process.argv[getProcessArgvBinIndex()];
164
+ return host.argv[getProcessArgvBinIndex()];
164
165
  }
165
166
  const nodeRequire = createRequire(import.meta.url);
166
167
  let previouslyVisitedConfigs = [];
@@ -2,6 +2,7 @@ import { readFileSync } from 'node:fs';
2
2
  import { createRequire } from 'node:module';
3
3
  import { normalize, resolve } from 'node:path';
4
4
  import { format } from 'node:util';
5
+ import { host } from './runtime.js';
5
6
  export function camelCase(str) {
6
7
  const isCamelCase = str !== str.toLowerCase() && str !== str.toUpperCase();
7
8
  if (!isCamelCase)
@@ -902,11 +903,10 @@ function sanitizeKey(key) {
902
903
  function stripQuotes(val) {
903
904
  return typeof val === 'string' && (val[0] === "'" || val[0] === '"') && val.at(-1) === val[0] ? val.substring(1, val.length - 1) : val;
904
905
  }
905
- const env = process.env;
906
906
  const nodeRequire = createRequire(import.meta.url);
907
907
  const parser = new YargsParser({
908
- cwd: process.cwd,
909
- env: () => env,
908
+ cwd: () => host.cwd(),
909
+ env: () => host.env,
910
910
  format,
911
911
  normalize,
912
912
  resolve,
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "burgee",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "An agent-native CLI framework, drop-in compatible with commander and yargs. One declaration; help, --json, --schema, --mcp and completions all projected from it.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
+ "sideEffects": [
8
+ "./dist/cli.js"
9
+ ],
7
10
  "engines": {
8
11
  "node": ">=24"
9
12
  },
@@ -13,6 +16,12 @@
13
16
  "import": "./dist/index.js",
14
17
  "default": "./dist/index.js"
15
18
  },
19
+ "./schema.json": "./dist/schema.json",
20
+ "./plugin": {
21
+ "types": "./dist/plugin.d.ts",
22
+ "import": "./dist/plugin.js",
23
+ "default": "./dist/plugin.js"
24
+ },
16
25
  "./brand": {
17
26
  "types": "./dist/brand.d.ts",
18
27
  "import": "./dist/brand.js",
@@ -66,7 +75,7 @@
66
75
  "locales"
67
76
  ],
68
77
  "scripts": {
69
- "build": "tsc -p tsconfig.build.json && node ../../scripts/strip-comments.mjs dist",
78
+ "build": "tsc -p tsconfig.build.json && node ../../scripts/schema-to-dist.mjs && node ../../scripts/strip-comments.mjs dist",
70
79
  "typecheck": "tsc -p tsconfig.json --noEmit",
71
80
  "test": "vitest run --passWithNoTests",
72
81
  "coverage": "vitest run --coverage.enabled",
@@ -96,9 +105,11 @@
96
105
  "provenance": true
97
106
  },
98
107
  "dependencies": {
99
- "linegauge": "^0.2.0",
100
- "roundel": "^0.3.0",
101
- "seniority": "^0.1.0"
108
+ "bellpull": "^0.1.0",
109
+ "closeout": "^0.2.0",
110
+ "linegauge": "^0.3.0",
111
+ "roundel": "^0.3.1",
112
+ "seniority": "^0.2.0"
102
113
  },
103
114
  "devDependencies": {
104
115
  "vitest": "^5.0.0"