burgee 0.4.0 → 0.5.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.
@@ -10,18 +10,14 @@
10
10
  * WCAG 2.2 sets 4.5:1 for body text and 3:1 for large text and for the parts of
11
11
  * a graphic you need in order to understand it. A logo's bars are the latter, so
12
12
  * 3:1 is the floor used here — see `AA`.
13
+ *
14
+ * The measuring is `roundel`'s, not ours. Colour is the layer below this one, and until
15
+ * 2026-09-09 both packages carried the same forty lines of WCAG luminance — identical
16
+ * constants, identical maths, differing only in which package name the hex error says.
17
+ * What is left here is the part that is actually about a burgee: which pairs of a flag's
18
+ * own colours have to clear the floor, and how to say so to a person running `burgee brand`.
13
19
  */
14
- /** The floors WCAG 2.2 sets, as ratios. */
15
- export declare const AA: {
16
- /** Body text against its background. */
17
- readonly TEXT: 4.5;
18
- /** Large text, UI components, and meaningful parts of a graphic. */
19
- readonly GRAPHIC: 3;
20
- };
21
- /** WCAG relative luminance. */
22
- export declare function luminance(hex: string): number;
23
- /** The WCAG contrast ratio between two colours. Order does not matter. */
24
- export declare function contrast(a: string, b: string): number;
20
+ import { AA, contrast, luminance } from 'roundel/contrast';
25
21
  /** Mix two colours in sRGB. Enough for reading a gradient stop, not for colour science. */
26
22
  export declare function mix(a: string, b: string, t: number): string;
27
23
  export interface ContrastFinding {
@@ -68,3 +64,5 @@ export interface AuditInput {
68
64
  * intrinsic pair and fails a ground has a page problem, not a logo problem.
69
65
  */
70
66
  export declare function auditBurgee(brand: AuditInput, grounds?: readonly string[]): ContrastFinding[];
67
+ /** Re-exported so a caller reading a burgee's contrast needs one import, not two. */
68
+ export { AA, contrast, luminance };
package/dist/contrast.js CHANGED
@@ -1,38 +1,6 @@
1
- export const AA = {
2
- TEXT: 4.5,
3
- GRAPHIC: 3,
4
- };
1
+ import { AA, channels, contrast, luminance } from 'roundel/contrast';
5
2
  const SRGB_MAX = 255;
6
- const LINEAR_THRESHOLD = 0.03928;
7
- const LINEAR_DIVISOR = 12.92;
8
- const GAMMA_OFFSET = 0.055;
9
- const GAMMA_SCALE = 1.055;
10
- const GAMMA_EXPONENT = 2.4;
11
- const LUMA = { r: 0.2126, g: 0.7152, b: 0.0722 };
12
- const CONTRAST_OFFSET = 0.05;
13
- const RED_AT = 1;
14
- const GREEN_AT = 3;
15
- const BLUE_AT = 5;
16
- const HEX_PAIRS = [RED_AT, GREEN_AT, BLUE_AT];
17
3
  const HEX_RADIX = 16;
18
- const SHORT_HEX_LENGTH = 4;
19
- function channels(hex) {
20
- const full = hex.length === SHORT_HEX_LENGTH
21
- ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`
22
- : hex;
23
- if (!/^#[0-9a-fA-F]{6}$/.test(full))
24
- throw new Error(`burgee: "${hex}" is not a hex colour`);
25
- const parsed = HEX_PAIRS.map((i) => Number.parseInt(full.slice(i, i + 2), HEX_RADIX) / SRGB_MAX);
26
- return parsed;
27
- }
28
- export function luminance(hex) {
29
- const [r, g, b] = channels(hex).map((v) => v <= LINEAR_THRESHOLD ? v / LINEAR_DIVISOR : ((v + GAMMA_OFFSET) / GAMMA_SCALE) ** GAMMA_EXPONENT);
30
- return LUMA.r * r + LUMA.g * g + LUMA.b * b;
31
- }
32
- export function contrast(a, b) {
33
- const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
34
- return (hi + CONTRAST_OFFSET) / (lo + CONTRAST_OFFSET);
35
- }
36
4
  export function mix(a, b, t) {
37
5
  const [ca, cb] = [channels(a), channels(b)];
38
6
  const hex = ca
@@ -91,3 +59,4 @@ export function auditBurgee(brand, grounds = []) {
91
59
  }
92
60
  return findings;
93
61
  }
62
+ export { AA, contrast, luminance };
package/dist/schema.d.ts CHANGED
@@ -42,10 +42,42 @@ export interface CommandSchema {
42
42
  plugin?: string;
43
43
  arguments: ArgumentSpec[];
44
44
  options: Record<string, OptionSpec>;
45
+ /**
46
+ * The constraints between options (S2/S6), which `validate.ts` already enforces and the
47
+ * schema did not publish. Without them an agent can only discover that `--a` conflicts
48
+ * with `--b` by sending both and reading exit 2 — a round trip per constraint, and under
49
+ * E1 an exit 2 means *rewrite the command*, so it may well send the same pair again.
50
+ *
51
+ * Omitted entirely when a command declares none, so a reader can tell "no constraints"
52
+ * from "constraints not published".
53
+ */
54
+ relations?: PublishedRelation[];
45
55
  examples: Example[];
46
56
  /** The arguments and options as one JSON Schema object — what an MCP tool call takes. */
47
57
  inputSchema: JsonSchema;
48
58
  }
59
+ /**
60
+ * A relation as JSON can carry it.
61
+ *
62
+ * `implies` takes either another option's name or a **predicate over the values**, and a
63
+ * function cannot be published. `JSON.stringify` turns it into `null` without a word, which
64
+ * would hand an agent `["force", null]` and let it conclude the constraint is malformed
65
+ * rather than unevaluable. So a predicate becomes the string `"(predicate)"`: the pair is
66
+ * still visible, and what is missing says so.
67
+ */
68
+ export type PublishedRelation = {
69
+ exactlyOneOf: readonly string[];
70
+ } | {
71
+ atLeastOneOf: readonly string[];
72
+ } | {
73
+ atMostOneOf: readonly string[];
74
+ } | {
75
+ conflicts: readonly string[];
76
+ } | {
77
+ implies: readonly [string, string];
78
+ };
79
+ /** The marker a predicate leaves behind. Not a name any option can have — it has parentheses. */
80
+ export declare const PREDICATE = "(predicate)";
49
81
  export interface ProgramSchema {
50
82
  schemaVersion: 1;
51
83
  name: string;
package/dist/schema.js CHANGED
@@ -1,4 +1,11 @@
1
1
  import { kebab } from './names.js';
2
+ export const PREDICATE = '(predicate)';
3
+ function publishable(relation) {
4
+ if (!('implies' in relation))
5
+ return relation;
6
+ const [option, consequent] = relation.implies;
7
+ return { implies: [option, typeof consequent === 'function' ? PREDICATE : consequent] };
8
+ }
2
9
  function argumentProperty(a) {
3
10
  const p = a.variadic === true ? { type: 'array', items: { type: 'string' } } : { type: 'string' };
4
11
  if (a.description !== undefined)
@@ -76,6 +83,8 @@ export function commandSchemaOf(node, root) {
76
83
  out.lazy = true;
77
84
  if (node.plugin !== undefined)
78
85
  out.plugin = node.plugin;
86
+ if (node.relations !== undefined && node.relations.length > 0)
87
+ out.relations = node.relations.map(publishable);
79
88
  return out;
80
89
  }
81
90
  export function runnable(manifest) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "burgee",
3
- "version": "0.4.0",
3
+ "version": "0.5.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",
@@ -95,6 +95,9 @@
95
95
  "access": "public",
96
96
  "provenance": true
97
97
  },
98
+ "dependencies": {
99
+ "roundel": "^0.3.0"
100
+ },
98
101
  "devDependencies": {
99
102
  "vitest": "^5.0.0"
100
103
  },