@noir-ai/cli 1.6.0 → 1.7.0-beta.1

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.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/dist/bin.js +81 -8
  3. package/dist/bin.js.map +1 -1
  4. package/dist/{chunk-SVFQGAOF.js → chunk-3E7ZT5OG.js} +5 -3
  5. package/dist/{chunk-SVFQGAOF.js.map → chunk-3E7ZT5OG.js.map} +1 -1
  6. package/dist/chunk-47ITYQ3A.js +203 -0
  7. package/dist/chunk-47ITYQ3A.js.map +1 -0
  8. package/dist/chunk-DQXQQDJN.js +310 -0
  9. package/dist/chunk-DQXQQDJN.js.map +1 -0
  10. package/dist/chunk-RYE3BUGP.js +174 -0
  11. package/dist/chunk-RYE3BUGP.js.map +1 -0
  12. package/dist/{chunk-YES5UCU5.js → chunk-WS7K4NKA.js} +59 -311
  13. package/dist/chunk-WS7K4NKA.js.map +1 -0
  14. package/dist/{create-7ERBL42K.js → create-P4M52LZZ.js} +6 -4
  15. package/dist/{create-7ERBL42K.js.map → create-P4M52LZZ.js.map} +1 -1
  16. package/dist/index.js +3 -2
  17. package/dist/install-XACGZ235.js +13 -0
  18. package/dist/install-XACGZ235.js.map +1 -0
  19. package/dist/{sync-SCAF6Z5H.js → sync-35DR6DNN.js} +5 -3
  20. package/dist/{sync-SCAF6Z5H.js.map → sync-35DR6DNN.js.map} +1 -1
  21. package/dist/tui/chunk-63KFZH6T.js +202 -0
  22. package/dist/tui/chunk-63KFZH6T.js.map +1 -0
  23. package/dist/tui/{chunk-YNEBQJXA.js → chunk-BDFQ5S3K.js} +59 -311
  24. package/dist/tui/chunk-BDFQ5S3K.js.map +1 -0
  25. package/dist/tui/chunk-CMGOOU7L.js +173 -0
  26. package/dist/tui/chunk-CMGOOU7L.js.map +1 -0
  27. package/dist/tui/chunk-L5ZKEOQV.js +309 -0
  28. package/dist/tui/chunk-L5ZKEOQV.js.map +1 -0
  29. package/dist/tui/{chunk-OMF7XZMN.js → chunk-LHT7M6DO.js} +5 -3
  30. package/dist/tui/{chunk-OMF7XZMN.js.map → chunk-LHT7M6DO.js.map} +1 -1
  31. package/dist/tui/{create-U2YJH5QC.js → create-IZSOFSO7.js} +6 -4
  32. package/dist/tui/{create-U2YJH5QC.js.map → create-IZSOFSO7.js.map} +1 -1
  33. package/dist/tui/index.js +86 -13
  34. package/dist/tui/index.js.map +1 -1
  35. package/dist/tui/install-357OEHOZ.js +12 -0
  36. package/dist/tui/install-357OEHOZ.js.map +1 -0
  37. package/dist/tui/{sync-VYRXCGK4.js → sync-32TP7XB6.js} +5 -3
  38. package/dist/tui/{sync-VYRXCGK4.js.map → sync-32TP7XB6.js.map} +1 -1
  39. package/dist/tui/update-7HWOY55V.js +15 -0
  40. package/dist/tui/update-7HWOY55V.js.map +1 -0
  41. package/dist/update-J3TAORFX.js +16 -0
  42. package/dist/update-J3TAORFX.js.map +1 -0
  43. package/package.json +9 -9
  44. package/dist/chunk-YES5UCU5.js.map +0 -1
  45. package/dist/tui/chunk-YNEBQJXA.js.map +0 -1
@@ -0,0 +1,173 @@
1
+ import {
2
+ installManagedNode
3
+ } from "./chunk-63KFZH6T.js";
4
+ import {
5
+ EXIT,
6
+ fail,
7
+ info,
8
+ success,
9
+ warn
10
+ } from "./chunk-L5ZKEOQV.js";
11
+
12
+ // src/commands/update.ts
13
+ import {
14
+ detectActiveMethod,
15
+ fetchLatestVersion,
16
+ loadProjectInfo,
17
+ readInstallRecord,
18
+ readUpdateCache,
19
+ runManagerCmd,
20
+ shouldCheckForUpdate,
21
+ writeUpdateCache
22
+ } from "@noir-ai/core";
23
+ var DEFAULT_UPDATE_CONFIG = {
24
+ checkEnabled: true,
25
+ checkIntervalHours: 24,
26
+ channel: "latest",
27
+ minVersion: "1.6.0",
28
+ display: "notice"
29
+ };
30
+ function buildUpdateTarget(opts) {
31
+ const targetSpec = opts.spec ?? opts.channel;
32
+ const isUpgrade = opts.latestKnown != null && opts.currentVersion != null && semverGt(opts.latestKnown, opts.currentVersion);
33
+ const floor = opts.minVersion ?? "1.6.0";
34
+ const belowMinVersion = opts.latestKnown != null && semverLt(opts.latestKnown, floor);
35
+ return {
36
+ method: opts.method,
37
+ targetSpec,
38
+ currentVersion: opts.currentVersion,
39
+ latestKnown: opts.latestKnown,
40
+ isUpgrade,
41
+ belowMinVersion
42
+ };
43
+ }
44
+ function semverGt(a, b) {
45
+ const pa = a.split(".").map((s) => Number(s) || 0);
46
+ const pb = b.split(".").map((s) => Number(s) || 0);
47
+ for (let i = 0; i < 3; i++) {
48
+ const x = pa[i] ?? 0;
49
+ const y = pb[i] ?? 0;
50
+ if (x !== y) return x > y;
51
+ }
52
+ return false;
53
+ }
54
+ function semverLt(a, b) {
55
+ const pa = a.split(".").map((s) => Number(s) || 0);
56
+ const pb = b.split(".").map((s) => Number(s) || 0);
57
+ for (let i = 0; i < 3; i++) {
58
+ const x = pa[i] ?? 0;
59
+ const y = pb[i] ?? 0;
60
+ if (x !== y) return x < y;
61
+ }
62
+ return false;
63
+ }
64
+ async function update(opts = {}) {
65
+ if (process.env.NOIR_DISABLE_UPDATES !== void 0) {
66
+ fail(
67
+ EXIT.USAGE,
68
+ "self-update is disabled (NOIR_DISABLE_UPDATES is set); update via your package manager or image rebuild.",
69
+ opts
70
+ );
71
+ return;
72
+ }
73
+ const method = detectActiveMethod();
74
+ const rec = readInstallRecord();
75
+ const currentVersion = rec?.version ?? null;
76
+ if (opts.check === true) {
77
+ const latest2 = await fetchLatestVersion("latest");
78
+ info(
79
+ latest2 ? `Latest: ${latest2} (you have ${currentVersion ?? "unknown"})` : "Could not reach the registry.",
80
+ opts
81
+ );
82
+ return;
83
+ }
84
+ const latest = await fetchLatestVersion("latest");
85
+ if (latest === null) {
86
+ info("Could not reach the registry.", opts);
87
+ return;
88
+ }
89
+ let minVersion = DEFAULT_UPDATE_CONFIG.minVersion;
90
+ try {
91
+ minVersion = loadProjectInfo(process.cwd()).config.update.minVersion;
92
+ } catch {
93
+ }
94
+ const target = buildUpdateTarget({
95
+ method,
96
+ channel: "latest",
97
+ spec: opts.spec,
98
+ currentVersion,
99
+ latestKnown: latest,
100
+ minVersion
101
+ });
102
+ if (target.belowMinVersion) {
103
+ warn(`Latest known ${target.latestKnown} is below the minVersion floor (${minVersion}).`);
104
+ fail(
105
+ EXIT.USAGE,
106
+ `refusing update to ${target.latestKnown} (below minVersion ${minVersion})`,
107
+ opts
108
+ );
109
+ }
110
+ if (!target.isUpgrade) {
111
+ info(`noir ${currentVersion} is up to date.`, opts);
112
+ return;
113
+ }
114
+ if (method === "native") {
115
+ const res = await installManagedNode({
116
+ version: target.targetSpec === "latest" ? void 0 : target.targetSpec,
117
+ env: process.env
118
+ });
119
+ if (!res.ok) fail(EXIT.ERROR, res.error ?? "update failed", opts);
120
+ success(`Updated to ${res.version}.`);
121
+ return;
122
+ }
123
+ const cmd = updateCmdFor(method, target.targetSpec);
124
+ if (!cmd)
125
+ fail(EXIT.USAGE, `cannot auto-update a ${method} install; use the manager directly`, opts);
126
+ const { code, stderr } = await runManagerCmd(cmd, { env: process.env });
127
+ if (code !== 0) fail(EXIT.ERROR, `update failed: ${stderr.slice(0, 300)}`, opts);
128
+ success("Updated.");
129
+ }
130
+ function updateCmdFor(method, spec) {
131
+ switch (method) {
132
+ case "npm":
133
+ return ["npm", "install", "-g", `@noir-ai/cli@${spec}`];
134
+ case "pnpm":
135
+ return ["pnpm", "add", "-g", `@noir-ai/cli@${spec}`];
136
+ case "yarn":
137
+ return ["yarn", "global", "add", `@noir-ai/cli@${spec}`];
138
+ case "bun":
139
+ return ["bun", "add", "-g", `@noir-ai/cli@${spec}`];
140
+ case "homebrew":
141
+ return ["brew", "upgrade", "noir"];
142
+ case "scoop":
143
+ return ["scoop", "update", "noir"];
144
+ default:
145
+ return null;
146
+ }
147
+ }
148
+ async function runAsyncUpdateCheck(opts) {
149
+ try {
150
+ const cache = readUpdateCache();
151
+ if (!shouldCheckForUpdate({ env: opts.env, configUpdate: opts.configUpdate, cache })) return;
152
+ const controller = new AbortController();
153
+ const timer = setTimeout(() => controller.abort(), 2e3);
154
+ const latest = await fetchLatestVersion(opts.configUpdate.channel, controller.signal);
155
+ clearTimeout(timer);
156
+ if (latest != null) {
157
+ writeUpdateCache({
158
+ lastCheckAt: (/* @__PURE__ */ new Date()).toISOString(),
159
+ latestVersion: latest,
160
+ channel: opts.configUpdate.channel
161
+ });
162
+ }
163
+ } catch {
164
+ }
165
+ }
166
+
167
+ export {
168
+ DEFAULT_UPDATE_CONFIG,
169
+ buildUpdateTarget,
170
+ update,
171
+ runAsyncUpdateCheck
172
+ };
173
+ //# sourceMappingURL=chunk-CMGOOU7L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/commands/update.ts"],"sourcesContent":["import {\n detectActiveMethod,\n fetchLatestVersion,\n loadProjectInfo,\n readInstallRecord,\n readUpdateCache,\n runManagerCmd,\n shouldCheckForUpdate,\n type UpdateConfigLike,\n writeUpdateCache,\n} from '@noir-ai/core';\nimport { type CliOptions, EXIT, fail, info, success, warn } from '../output.js';\nimport { installManagedNode } from './install.js';\n\nexport const DEFAULT_UPDATE_CONFIG: UpdateConfigLike = {\n checkEnabled: true,\n checkIntervalHours: 24,\n channel: 'latest',\n minVersion: '1.6.0',\n display: 'notice',\n};\n\nexport interface UpdateOptions extends CliOptions {\n check?: boolean;\n spec?: string;\n}\n\nexport interface UpdateTarget {\n method: string;\n targetSpec: string;\n currentVersion: string | null;\n latestKnown: string | null;\n isUpgrade: boolean;\n /**\n * I2 — `update.minVersion` floor (config.ts:238). True when the latest-known\n * version the registry returned is below the configured floor (e.g. a\n * beta/prerelease channel lag, or a yanked dist-tag). Enforced in\n * {@link update} with the same warn/refuse pattern as the downgrade guard.\n */\n belowMinVersion: boolean;\n}\n\nexport function buildUpdateTarget(opts: {\n method: string;\n channel: string;\n spec?: string;\n currentVersion: string | null;\n latestKnown: string | null;\n /**\n * The `update.minVersion` floor from config (default `'1.6.0'`). When\n * omitted, the config default applies. See I2.\n */\n minVersion?: string;\n}): UpdateTarget {\n const targetSpec = opts.spec ?? opts.channel;\n // Semver downgrade guard (T6 hardening): only treat the latest-known version\n // as an upgrade when it is STRICTLY NEWER than the current one. The prior\n // inequality check (`latestKnown !== currentVersion`) would treat a registry\n // that returned an OLDER version (e.g. beta/prerelease channel lag, or a\n // pinned `--spec` older than installed) as an \"upgrade\" and silently\n // downgrade the install.\n const isUpgrade =\n opts.latestKnown != null &&\n opts.currentVersion != null &&\n semverGt(opts.latestKnown, opts.currentVersion);\n // I2 — minVersion floor: refuse a registry-offered version below the floor.\n // null latestKnown is handled separately (registry-unreachable branch).\n const floor = opts.minVersion ?? '1.6.0';\n const belowMinVersion = opts.latestKnown != null && semverLt(opts.latestKnown, floor);\n return {\n method: opts.method,\n targetSpec,\n currentVersion: opts.currentVersion,\n latestKnown: opts.latestKnown,\n isUpgrade,\n belowMinVersion,\n };\n}\n\n/**\n * Per-segment numeric semver comparison (major.minor.patch). Returns true when\n * `a` is strictly greater than `b`. Pre-release suffixes are ignored — Noir\n * versioning is `MAJOR.MINOR.PATCH` only, and the registry's dist-tag is the\n * source of truth for \"latest\". Non-numeric segments coerce to 0. Used here\n * instead of a full semver library to keep the CLI's dependency surface\n * unchanged (the same helper lives in install.ts for the downgrade guard).\n */\nfunction semverGt(a: string, b: string): boolean {\n const pa = a.split('.').map((s) => Number(s) || 0);\n const pb = b.split('.').map((s) => Number(s) || 0);\n for (let i = 0; i < 3; i++) {\n const x = pa[i] ?? 0;\n const y = pb[i] ?? 0;\n if (x !== y) return x > y;\n }\n return false;\n}\n\n/**\n * Per-segment numeric semver `<` (I2 — minVersion floor). Same comparison\n * discipline as {@link semverGt} / install.ts's downgrade guard: numeric per\n * segment, non-numeric → 0. Returns true when `a` is strictly less than `b`.\n */\nfunction semverLt(a: string, b: string): boolean {\n const pa = a.split('.').map((s) => Number(s) || 0);\n const pb = b.split('.').map((s) => Number(s) || 0);\n for (let i = 0; i < 3; i++) {\n const x = pa[i] ?? 0;\n const y = pb[i] ?? 0;\n if (x !== y) return x < y;\n }\n return false;\n}\n\nexport async function update(opts: UpdateOptions = {}): Promise<void> {\n // NOIR_DISABLE_UPDATES is the hard kill-switch for the SELF-UPDATE surface\n // (distinct from NOIR_DISABLE_UPDATE_CHECK, which only gags the background\n // version check). When set, `noir update` refuses to run at all — enterprises\n // can pin this in the environment to enforce \"updates flow only through the\n // package manager / image rebuild, never from inside the CLI\". `fail` is\n // `: never` (always throws) — the explicit `return` is defensive.\n if (process.env.NOIR_DISABLE_UPDATES !== undefined) {\n fail(\n EXIT.USAGE,\n 'self-update is disabled (NOIR_DISABLE_UPDATES is set); update via your package manager or image rebuild.',\n opts,\n );\n return;\n }\n\n const method = detectActiveMethod();\n const rec = readInstallRecord();\n const currentVersion = rec?.version ?? null;\n\n if (opts.check === true) {\n const latest = await fetchLatestVersion('latest');\n info(\n latest\n ? `Latest: ${latest} (you have ${currentVersion ?? 'unknown'})`\n : 'Could not reach the registry.',\n opts,\n );\n return;\n }\n\n // Fetch latest (network; timeout-bound).\n const latest = await fetchLatestVersion('latest');\n // T6 hardening: when the registry was unreachable (fetch returned null), say\n // so explicitly — mirroring `--check` — instead of falling through to the\n // \"up to date\" branch (which the old inequality-based isUpgrade would print\n // because `null != currentVersion`).\n if (latest === null) {\n info('Could not reach the registry.', opts);\n return;\n }\n // I2 — read the `update.minVersion` floor from the project config (falls\n // back to the config default '1.6.0' when the project isn't initialized or\n // the block is absent). Same try/catch pattern as home.ts's update-config read.\n let minVersion = DEFAULT_UPDATE_CONFIG.minVersion;\n try {\n minVersion = loadProjectInfo(process.cwd()).config.update.minVersion;\n } catch {\n // Not initialized yet — the config default applies.\n }\n const target = buildUpdateTarget({\n method,\n channel: 'latest',\n spec: opts.spec,\n currentVersion,\n latestKnown: latest,\n minVersion,\n });\n\n // I2 — refuse to install a registry-offered version below the configured\n // minVersion floor (same warn/refuse pattern as install.ts's downgrade guard).\n // Checked before the isUpgrade branch: a below-floor offer is unsafe even if\n // it happens to be newer than the (very old) current install.\n if (target.belowMinVersion) {\n warn(`Latest known ${target.latestKnown} is below the minVersion floor (${minVersion}).`);\n fail(\n EXIT.USAGE,\n `refusing update to ${target.latestKnown} (below minVersion ${minVersion})`,\n opts,\n );\n }\n\n if (!target.isUpgrade) {\n info(`noir ${currentVersion} is up to date.`, opts);\n return;\n }\n\n if (method === 'native') {\n const res = await installManagedNode({\n version: target.targetSpec === 'latest' ? undefined : target.targetSpec,\n env: process.env,\n });\n if (!res.ok) fail(EXIT.ERROR, res.error ?? 'update failed', opts);\n success(`Updated to ${res.version}.`);\n return;\n }\n\n // npm/pnpm/yarn/bun/homebrew/scoop -> reinstall via the same manager.\n const cmd = updateCmdFor(method, target.targetSpec);\n if (!cmd)\n fail(EXIT.USAGE, `cannot auto-update a ${method} install; use the manager directly`, opts);\n const { code, stderr } = await runManagerCmd(cmd, { env: process.env });\n if (code !== 0) fail(EXIT.ERROR, `update failed: ${stderr.slice(0, 300)}`, opts);\n success('Updated.');\n}\n\nfunction updateCmdFor(method: string, spec: string): string[] | null {\n switch (method) {\n case 'npm':\n return ['npm', 'install', '-g', `@noir-ai/cli@${spec}`];\n case 'pnpm':\n return ['pnpm', 'add', '-g', `@noir-ai/cli@${spec}`];\n case 'yarn':\n return ['yarn', 'global', 'add', `@noir-ai/cli@${spec}`];\n case 'bun':\n return ['bun', 'add', '-g', `@noir-ai/cli@${spec}`];\n case 'homebrew':\n return ['brew', 'upgrade', 'noir'];\n case 'scoop':\n return ['scoop', 'update', 'noir'];\n default:\n return null;\n }\n}\n\n/** Non-blocking, time-boxed startup check. Writes the cache on success; silent on any failure. */\nexport async function runAsyncUpdateCheck(opts: {\n env: NodeJS.ProcessEnv;\n configUpdate: UpdateConfigLike;\n quiet: boolean;\n}): Promise<void> {\n try {\n const cache = readUpdateCache();\n if (!shouldCheckForUpdate({ env: opts.env, configUpdate: opts.configUpdate, cache })) return;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 2000);\n const latest = await fetchLatestVersion(opts.configUpdate.channel, controller.signal);\n clearTimeout(timer);\n if (latest != null) {\n writeUpdateCache({\n lastCheckAt: new Date().toISOString(),\n latestVersion: latest,\n channel: opts.configUpdate.channel,\n });\n }\n // Non-blocking: never print in quiet/CI/non-TTY; a mismatch only nudges.\n } catch {\n // silent on any failure — this is a non-blocking background check\n }\n}\n"],"mappings":"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","names":["latest"]}
@@ -0,0 +1,309 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/output.ts
9
+ import Table from "cli-table3";
10
+ import { CommanderError } from "commander";
11
+ import ora from "ora";
12
+
13
+ // src/theme.ts
14
+ import pc from "picocolors";
15
+ var FORCE = pc.createColors(true);
16
+ var c = {
17
+ /** Green — success / healthy. */
18
+ ok: (s) => useColor() ? FORCE.green(s) : s,
19
+ /** Yellow — degraded but usable. */
20
+ warn: (s) => useColor() ? FORCE.yellow(s) : s,
21
+ /** Red — reserved strictly for ERROR. Never a table header. */
22
+ error: (s) => useColor() ? FORCE.red(s) : s,
23
+ /** Cyan — informational / brand-neutral accent for labels. */
24
+ info: (s) => useColor() ? FORCE.cyan(s) : s,
25
+ /** Blue — the Midnight Cobalt brand role (banner / accent). */
26
+ accent: (s) => useColor() ? FORCE.blue(s) : s,
27
+ /** Dim — secondary text, table borders when color is on. */
28
+ dim: (s) => useColor() ? FORCE.dim(s) : s,
29
+ /** Bold — emphasis (table headers compose this with `info`). */
30
+ bold: (s) => useColor() ? FORCE.bold(s) : s
31
+ };
32
+ var BADGE_SYMBOL = {
33
+ ok: "\u2713",
34
+ warn: "\u26A0",
35
+ error: "\u2717",
36
+ info: "\u2139"
37
+ };
38
+ function badge(state, label = state) {
39
+ const text = `${BADGE_SYMBOL[state]} ${label}`;
40
+ switch (state) {
41
+ case "ok":
42
+ return c.ok(text);
43
+ case "warn":
44
+ return c.warn(text);
45
+ case "error":
46
+ return c.error(text);
47
+ case "info":
48
+ return c.info(text);
49
+ }
50
+ }
51
+ function envFlagSet(name) {
52
+ const v = process.env[name];
53
+ return v !== void 0 && v !== "";
54
+ }
55
+ function isCiEnv() {
56
+ const v = process.env.CI;
57
+ if (v === void 0 || v === "") return false;
58
+ return v !== "0" && v !== "false";
59
+ }
60
+ function useColor() {
61
+ if (envFlagSet("NO_COLOR")) return false;
62
+ if (process.env.CLICOLOR_FORCE === "1") return true;
63
+ if (isCiEnv()) return false;
64
+ return pc.isColorSupported;
65
+ }
66
+ function accessibleMode() {
67
+ return envFlagSet("NOIR_ACCESSIBLE");
68
+ }
69
+ function terminalWidth() {
70
+ const fromEnv = process.env.COLUMNS;
71
+ if (fromEnv !== void 0 && fromEnv !== "") {
72
+ const n = Number(fromEnv);
73
+ if (Number.isInteger(n) && n > 0) return Math.max(n, 20);
74
+ }
75
+ const cols = process.stdout.columns;
76
+ if (typeof cols === "number" && cols > 0) return Math.max(cols, 20);
77
+ return 80;
78
+ }
79
+
80
+ // src/output.ts
81
+ var EXIT = {
82
+ OK: 0,
83
+ ERROR: 1,
84
+ USAGE: 2,
85
+ NOT_FOUND: 3,
86
+ DAEMON_DOWN: 4,
87
+ CANCELLED: 5
88
+ };
89
+ var NoirCliError = class extends Error {
90
+ exitCode;
91
+ constructor(exitCode, message) {
92
+ super(message);
93
+ this.name = "NoirCliError";
94
+ this.exitCode = exitCode;
95
+ }
96
+ };
97
+ var NOIR_ERROR_CODE = "noir.error";
98
+ function isJsonMode(opts) {
99
+ return opts.json === true;
100
+ }
101
+ function isQuietMode(opts) {
102
+ return opts.quiet === true;
103
+ }
104
+ function isNoInput(opts = {}) {
105
+ return opts.noInput === true || opts.input === false;
106
+ }
107
+ function envFlagSet2(name) {
108
+ const v = process.env[name];
109
+ return v !== void 0 && v !== "";
110
+ }
111
+ function isInteractive(opts = {}) {
112
+ if (isJsonMode(opts) || isNoInput(opts)) return false;
113
+ if (isCiEnv() || envFlagSet2("NO_COLOR")) return false;
114
+ return process.stdin.isTTY === true && process.stdout.isTTY === true;
115
+ }
116
+ function resolveInteractive() {
117
+ if (flaggedNonInteractiveCli()) return false;
118
+ return isInteractive();
119
+ }
120
+ function flaggedNonInteractiveCli() {
121
+ const v = process.env.NOIR_NON_INTERACTIVE;
122
+ return v !== void 0 && v !== "";
123
+ }
124
+ function json(obj) {
125
+ process.stdout.write(`${JSON.stringify(obj)}
126
+ `);
127
+ }
128
+ function log(msg, opts = {}) {
129
+ if (isJsonMode(opts) || isQuietMode(opts)) return;
130
+ process.stderr.write(`${msg}
131
+ `);
132
+ }
133
+ function info(msg, opts = {}) {
134
+ if (isJsonMode(opts) || isQuietMode(opts)) return;
135
+ process.stderr.write(`${c.info(msg)}
136
+ `);
137
+ }
138
+ function success(msg, opts = {}) {
139
+ if (isJsonMode(opts) || isQuietMode(opts)) return;
140
+ process.stderr.write(`${c.ok(msg)}
141
+ `);
142
+ }
143
+ function warn(msg, opts = {}) {
144
+ if (isJsonMode(opts)) return;
145
+ process.stderr.write(`${c.warn(msg)}
146
+ `);
147
+ }
148
+ function error(msg, opts = {}) {
149
+ if (isJsonMode(opts)) return;
150
+ process.stderr.write(`${c.error(msg)}
151
+ `);
152
+ }
153
+ function tip(msg, opts = {}) {
154
+ if (isJsonMode(opts) || opts.noTips === true) return;
155
+ process.stderr.write(`${c.warn(msg)}
156
+ `);
157
+ }
158
+ function table(rows, cols, opts = {}) {
159
+ if (isJsonMode(opts)) return;
160
+ if (rows.length === 0) {
161
+ info("(no rows)", opts);
162
+ return;
163
+ }
164
+ const t = new Table({
165
+ head: cols.map((col) => c.bold(c.info(col))),
166
+ // Empty arrays ⇒ cli-table3 applies NO @colors/colors wrap (neither the
167
+ // default red header nor a colored border). All color is ours, via theme.
168
+ style: { head: [], border: [] },
169
+ colWidths: computeColWidths(rows, cols),
170
+ wordWrap: true,
171
+ truncate: "\u2026"
172
+ });
173
+ for (const row of rows) {
174
+ t.push(cols.map((col) => formatCell(row[col])));
175
+ }
176
+ process.stderr.write(`${t.toString()}
177
+ `);
178
+ }
179
+ function computeColWidths(rows, cols) {
180
+ const n = cols.length;
181
+ if (n === 0) return [];
182
+ const headerLen = cols.map((col) => col.length);
183
+ const natural = cols.map((col, i) => {
184
+ let max = Math.max(headerLen[i] ?? col.length, 3);
185
+ for (const row of rows) {
186
+ const len = formatCell(row[col]).length;
187
+ if (len > max) max = len;
188
+ }
189
+ return max;
190
+ });
191
+ const contentBudget = Math.max(n * 4, terminalWidth() - 3 * n - 1);
192
+ const naturalSum = natural.reduce((a, b) => a + b, 0);
193
+ if (naturalSum <= contentBudget) {
194
+ return natural.map((w) => w + 2);
195
+ }
196
+ const content = natural.slice();
197
+ let sum = naturalSum;
198
+ const floor = headerLen.map((h) => Math.max(h, 3));
199
+ while (sum > contentBudget) {
200
+ let idx = -1;
201
+ let widest = -1;
202
+ for (let i = 0; i < n; i++) {
203
+ const c2 = content[i] ?? 0;
204
+ const f = floor[i] ?? 3;
205
+ if (c2 > f && c2 > widest) {
206
+ widest = c2;
207
+ idx = i;
208
+ }
209
+ }
210
+ if (idx === -1) break;
211
+ const overshoot = sum - contentBudget;
212
+ const reducible = (content[idx] ?? 0) - (floor[idx] ?? 3);
213
+ const cut = Math.min(overshoot, reducible);
214
+ content[idx] = (content[idx] ?? 0) - cut;
215
+ sum -= cut;
216
+ }
217
+ return content.map((w) => w + 2);
218
+ }
219
+ function formatCell(value) {
220
+ if (value === void 0 || value === null) return "";
221
+ if (typeof value === "string") return value;
222
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
223
+ return String(value);
224
+ }
225
+ return JSON.stringify(value);
226
+ }
227
+ function definitionList(rows, opts = {}) {
228
+ table(
229
+ rows.map((r) => ({ Field: r.label, Value: formatCell(r.value) })),
230
+ ["Field", "Value"],
231
+ opts
232
+ );
233
+ }
234
+ function fail(exitCode, message, opts = {}) {
235
+ if (isJsonMode(opts)) {
236
+ process.stdout.write(`${JSON.stringify({ ok: false, error: { code: exitCode, message } })}
237
+ `);
238
+ } else if (message.length > 0) {
239
+ process.stderr.write(`${message}
240
+ `);
241
+ }
242
+ throw new CommanderError(exitCode, NOIR_ERROR_CODE, message);
243
+ }
244
+ function requireInteractive(opts, hint) {
245
+ if (!isInteractive(opts)) {
246
+ fail(
247
+ EXIT.USAGE,
248
+ `${hint} needs an interactive terminal, but input is disabled (non-TTY, --no-input, --json, CI, or NO_COLOR). Re-run in a TTY or supply the value as a flag.`,
249
+ opts
250
+ );
251
+ }
252
+ }
253
+ function commanderExitCode(err) {
254
+ switch (err.code) {
255
+ case "commander.helpDisplayed":
256
+ case "commander.versionDisplayed":
257
+ case "commander.version":
258
+ return EXIT.OK;
259
+ case "commander.unknownCommand":
260
+ return EXIT.NOT_FOUND;
261
+ default:
262
+ return EXIT.USAGE;
263
+ }
264
+ }
265
+ function inferExitCode(err) {
266
+ if (err instanceof NoirCliError) return err.exitCode;
267
+ if (err instanceof CommanderError) {
268
+ if (err.code.startsWith("noir.")) return err.exitCode;
269
+ return commanderExitCode(err);
270
+ }
271
+ return EXIT.ERROR;
272
+ }
273
+ function handleError(err) {
274
+ if (err instanceof NoirCliError) {
275
+ if (err.message.length > 0) process.stderr.write(`${err.message}
276
+ `);
277
+ } else if (err instanceof CommanderError) {
278
+ } else {
279
+ process.stderr.write(`noir: ${err instanceof Error ? err.message : String(err)}
280
+ `);
281
+ }
282
+ process.exitCode = inferExitCode(err);
283
+ }
284
+
285
+ export {
286
+ __require,
287
+ c,
288
+ badge,
289
+ useColor,
290
+ accessibleMode,
291
+ terminalWidth,
292
+ EXIT,
293
+ NoirCliError,
294
+ isInteractive,
295
+ resolveInteractive,
296
+ json,
297
+ log,
298
+ info,
299
+ success,
300
+ warn,
301
+ error,
302
+ tip,
303
+ table,
304
+ definitionList,
305
+ fail,
306
+ requireInteractive,
307
+ handleError
308
+ };
309
+ //# sourceMappingURL=chunk-L5ZKEOQV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/output.ts","../../src/theme.ts"],"sourcesContent":["// S9 t2 — centralized output + exit-code infrastructure for `@noir-ai/cli`.\n//\n// Stream discipline (S9): machine-readable data → stdout; every other\n// diagnostic (progress, warnings, errors, tables, help) → stderr. Under `--json`\n// the decorated stderr helpers are silenced so stdout stays pristine JSON, and\n// `fail()` emits a structured `{ok:false,error}` envelope to stdout instead.\n//\n// Decoration (picocolors / cli-table3 / ora) auto-disables under `--json`,\n// `--quiet`, `CI`, `NO_COLOR`, or a non-TTY, so the same code path is safe in an\n// interactive shell, a pipe, and CI.\n//\n// Exit codes (S9): 0 ok · 1 error · 2 usage · 3 not-found · 4 daemon-down ·\n// 5 cancelled. These constants live HERE (the single source of truth); bin.ts\n// re-exports them so existing imports from `./bin.js` keep working.\n\nimport Table from 'cli-table3';\nimport { CommanderError } from 'commander';\nimport ora, { type Ora } from 'ora';\nimport { c, isCiEnv, terminalWidth } from './theme.js';\n\n// ---------------------------------------------------------------------------\n// Exit-code contract + error types\n// ---------------------------------------------------------------------------\nexport const EXIT = {\n OK: 0,\n ERROR: 1,\n USAGE: 2,\n NOT_FOUND: 3,\n DAEMON_DOWN: 4,\n CANCELLED: 5,\n} as const;\n\nexport type ExitCode = (typeof EXIT)[keyof typeof EXIT];\n\n/**\n * Application-level CLI error carrying an S9 exit code. Thrown directly by\n * bin.ts for legacy usage paths; `fail()` is the ergonomic throw helper.\n * `inferExitCode` / `handleError` map it onto `process.exitCode`.\n */\nexport class NoirCliError extends Error {\n readonly exitCode: number;\n constructor(exitCode: number, message: string) {\n super(message);\n this.name = 'NoirCliError';\n this.exitCode = exitCode;\n }\n}\n\n/**\n * The `code` stamped onto every CommanderError our own `fail()` throws, so\n * `inferExitCode` can tell \"we threw this on purpose with an authoritative\n * exitCode\" apart from \"commander threw this for help/usage/unknown-command\"\n * (which must be remapped onto the S9 contract by `commanderExitCode`).\n */\nconst NOIR_ERROR_CODE = 'noir.error';\n\n// ---------------------------------------------------------------------------\n// Global-option shape. Commander stores `--no-input` under the attribute\n// `input` (default `true`; the flag sets it `false`) — see commander's\n// `Option.attributeName()` which strips the leading `no-`. Both `input`\n// (commander's real key) and `noInput` (the spec's intent) are accepted so\n// callers may pass either commander's raw globals or a hand-built object.\n// ---------------------------------------------------------------------------\nexport interface CliOptions {\n readonly json?: boolean;\n readonly quiet?: boolean;\n readonly verbose?: boolean;\n /** Commander's storage for `--no-input` (`false` ⇒ no input). */\n readonly input?: boolean;\n /** Convenience alias matching the `--no-input` intent (`true` ⇒ no input). */\n readonly noInput?: boolean;\n /** TUI-policy flag. `false` (`--no-tui`) forces bare `noir` onto the\n * non-interactive `status` path even in a TTY; `true` (`--tui`) is an\n * advisory hint that still requires a TTY; absent (auto) defers to\n * {@link isInteractive}. Advisory only — never hard-gates a subcommand. */\n readonly tui?: boolean;\n /** Hint-suppression flag (`--no-tips`). When `true`, redirect /\n * deprecation hints (and any other {@link tip} output) are silenced for\n * CI / log-friendly runs. */\n readonly noTips?: boolean;\n}\n\nfunction isJsonMode(opts: CliOptions): boolean {\n return opts.json === true;\n}\n\nfunction isQuietMode(opts: CliOptions): boolean {\n return opts.quiet === true;\n}\n\n/** True when the user has asked for no interactive input (either spelling). */\nexport function isNoInput(opts: CliOptions = {}): boolean {\n return opts.noInput === true || opts.input === false;\n}\n\nfunction envFlagSet(name: string): boolean {\n // NO_COLOR spec: present AND non-empty (regardless of value) disables color.\n const v = process.env[name];\n return v !== undefined && v !== '';\n}\n\n// `isCiEnv` is imported from ./theme.js (the color authority) — see note there.\n\n// ---------------------------------------------------------------------------\n// Interactivity gate. Drives both the @clack home menu and the\n// decoration of every helper below. Requires BOTH stdin and stdout to be TTYs:\n// @clack reads keypresses from stdin while ora/picocolors render to stdout.\n// ---------------------------------------------------------------------------\nexport function isInteractive(opts: CliOptions = {}): boolean {\n if (isJsonMode(opts) || isNoInput(opts)) return false;\n if (isCiEnv() || envFlagSet('NO_COLOR')) return false;\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n}\n\n/**\n * Derive the explicit `interactive` flag the scaffold engine reads (via\n * {@link ScaffoldOptions.interactive}) from the bridge bin.ts owns. The bin's\n * `preAction` sets `NOIR_NON_INTERACTIVE=1` under `--json`/`--no-input`; this\n * helper folds that with the {@link isInteractive} TTY/CI/NO_COLOR gate so a\n * single boolean flows into the engine + `buildConflictOpts`. The ENGINE itself\n * never reads `process.env` for interactivity — only this CLI helper does.\n */\nexport function resolveInteractive(): boolean {\n if (flaggedNonInteractiveCli()) return false;\n return isInteractive();\n}\n\n/** True when the bin's `preAction` flagged this invocation non-interactive\n * (`--json` / `--no-input` → `NOIR_NON_INTERACTIVE`). CLI-internal; the engine\n * reads {@link ScaffoldOptions.interactive} instead. */\nfunction flaggedNonInteractiveCli(): boolean {\n const v = process.env.NOIR_NON_INTERACTIVE;\n return v !== undefined && v !== '';\n}\n\n// ---------------------------------------------------------------------------\n// Data output (stdout). The ONLY helper here that writes to stdout; under\n// `--json` a command calls this exactly once with its full payload and never\n// mixes other stdout writes, keeping machine output pristine.\n// ---------------------------------------------------------------------------\nexport function json(obj: unknown): void {\n process.stdout.write(`${JSON.stringify(obj)}\\n`);\n}\n\n// ---------------------------------------------------------------------------\n// Human diagnostics (stderr). picocolors auto-strips ANSI under NO_COLOR /\n// non-TTY, and each helper additionally short-circuits under `--json`\n// (decoration off, payload is the output) — and `info`/`log`/`success` also\n// under `--quiet`. `warn`/`error` survive `--quiet` (they carry signal).\n// ---------------------------------------------------------------------------\nexport function log(msg: string, opts: CliOptions = {}): void {\n if (isJsonMode(opts) || isQuietMode(opts)) return;\n process.stderr.write(`${msg}\\n`);\n}\n\nexport function info(msg: string, opts: CliOptions = {}): void {\n if (isJsonMode(opts) || isQuietMode(opts)) return;\n process.stderr.write(`${c.info(msg)}\\n`);\n}\n\nexport function success(msg: string, opts: CliOptions = {}): void {\n if (isJsonMode(opts) || isQuietMode(opts)) return;\n process.stderr.write(`${c.ok(msg)}\\n`);\n}\n\nexport function warn(msg: string, opts: CliOptions = {}): void {\n if (isJsonMode(opts)) return;\n process.stderr.write(`${c.warn(msg)}\\n`);\n}\n\nexport function error(msg: string, opts: CliOptions = {}): void {\n if (isJsonMode(opts)) return;\n process.stderr.write(`${c.error(msg)}\\n`);\n}\n\n/**\n * Redirect / deprecation hint (stderr). Silenced under `--json` (a CI\n * consumer's stdout envelope must stay pristine) AND under `--no-tips`\n * ({@link CliOptions.noTips}). This is the ONLY helper deprecation / redirect\n * notices should use, so a single `--no-tips` flag quiets them all in CI / logs.\n * Style matches {@link warn} (these are advisory, not errors).\n */\nexport function tip(msg: string, opts: CliOptions = {}): void {\n if (isJsonMode(opts) || opts.noTips === true) return;\n process.stderr.write(`${c.warn(msg)}\\n`);\n}\n\n// ---------------------------------------------------------------------------\n// Tables (stderr). Suppressed entirely under `--json` — the command has\n// already emitted the rows as a JSON array via `json()`.\n//\n// Design: cli-table3 styles headers/borders via `@colors/colors`\n// (whose NO_COLOR/TTY semantics differ from picocolors), which painted EVERY\n// header red while the body stripped — RED is now reserved strictly for ERROR.\n// We bypass `@colors/colors` entirely by passing EMPTY `style.head`/`style.border`\n// arrays (cli-table3's `wrapWithStyleColors` early-returns on length 0) and\n// PRE-COLOR the header strings ourselves via `theme.c` (picocolors). Result:\n// the header, border, and body all strip consistently under NO_COLOR / non-TTY,\n// because picocolors is the SOLE color authority. Responsive `colWidths` are\n// computed from `terminalWidth()` so tables never overflow; `wordWrap` keeps\n// free-text cells readable, and `truncate: '…'` caps any single over-long token.\n// ---------------------------------------------------------------------------\nexport function table(\n rows: readonly Record<string, unknown>[],\n cols: readonly string[],\n opts: CliOptions = {},\n): void {\n if (isJsonMode(opts)) return;\n if (rows.length === 0) {\n info('(no rows)', opts);\n return;\n }\n const t = new Table({\n head: cols.map((col) => c.bold(c.info(col))),\n // Empty arrays ⇒ cli-table3 applies NO @colors/colors wrap (neither the\n // default red header nor a colored border). All color is ours, via theme.\n style: { head: [], border: [] },\n colWidths: computeColWidths(rows, cols),\n wordWrap: true,\n truncate: '…',\n });\n for (const row of rows) {\n t.push(cols.map((col) => formatCell(row[col])));\n }\n process.stderr.write(`${t.toString()}\\n`);\n}\n\n/**\n * Compute per-column widths (cli-table3 `colWidths`, which INCLUDE each column's\n * 2 padding chars) that fit `terminalWidth()`. Strategy:\n *\n * 1. Measure each column's NATURAL content width (longest cell, at least the\n * header label so a header never wraps/truncates).\n * 2. If the natural total fits, use it as-is — every cell renders whole.\n * 3. Otherwise GREEDILY TRIM ONLY THE WIDEST column (down to its header width)\n * until the row fits. Narrow columns (paths, ids, statuses) keep their full\n * width — they're single tokens that can't word-wrap, so truncating them\n * loses information. The widest column is the free-text one (descriptions,\n * details, snippets); it has spaces and absorbs the shrink via `wordWrap`.\n *\n * cli-table3 accepts only positive integers (negatives collapse). Each returned\n * width is `content + 2` to reserve the column's padding, so the content area\n * equals the measured width and the math against `terminalWidth()` is exact.\n */\nfunction computeColWidths(\n rows: readonly Record<string, unknown>[],\n cols: readonly string[],\n): number[] {\n const n = cols.length;\n if (n === 0) return [];\n const headerLen = cols.map((col) => col.length);\n const natural = cols.map((col, i) => {\n let max = Math.max(headerLen[i] ?? col.length, 3);\n for (const row of rows) {\n const len = formatCell(row[col]).length;\n if (len > max) max = len;\n }\n return max;\n });\n // cli-table3 row overhead: per column 1 left border + 2 padding, plus a final\n // right border ⇒ 3n + 1 non-content chars. `contentBudget` is what remains for\n // the sum of column CONTENT areas.\n const contentBudget = Math.max(n * 4, terminalWidth() - 3 * n - 1);\n const naturalSum = natural.reduce((a, b) => a + b, 0);\n if (naturalSum <= contentBudget) {\n return natural.map((w) => w + 2);\n }\n // Overflow: greedily cut the widest reducible column (≥ its header width).\n const content = natural.slice();\n let sum = naturalSum;\n const floor = headerLen.map((h) => Math.max(h, 3));\n while (sum > contentBudget) {\n let idx = -1;\n let widest = -1;\n for (let i = 0; i < n; i++) {\n const c = content[i] ?? 0;\n const f = floor[i] ?? 3;\n if (c > f && c > widest) {\n widest = c;\n idx = i;\n }\n }\n if (idx === -1) break; // every column is at its header floor — stop\n const overshoot = sum - contentBudget;\n const reducible = (content[idx] ?? 0) - (floor[idx] ?? 3);\n const cut = Math.min(overshoot, reducible);\n content[idx] = (content[idx] ?? 0) - cut;\n sum -= cut;\n }\n return content.map((w) => w + 2);\n}\n\nfunction formatCell(value: unknown): string {\n if (value === undefined || value === null) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n return String(value);\n }\n return JSON.stringify(value);\n}\n\n// ---------------------------------------------------------------------------\n// Definition list (stderr). A two-column Field/Value rendering for snapshot-\n// shaped output (status / task / context-status). `status.ts` hand-rolled this\n// exact shape; this generalizes it. Rendered via the same responsive `table()`,\n// so it inherits the clean (non-red) header + NO_COLOR behavior automatically.\n// ---------------------------------------------------------------------------\nexport interface DefinitionRow {\n /** Field label (left column). */\n label: string;\n /** Field value; coerced to a string the same way table cells are. */\n value: unknown;\n}\n\nexport function definitionList(rows: readonly DefinitionRow[], opts: CliOptions = {}): void {\n table(\n rows.map((r) => ({ Field: r.label, Value: formatCell(r.value) })),\n ['Field', 'Value'],\n opts,\n );\n}\n\n/** Render a single `label: value` line to stderr (human only). */\nexport function kv(label: string, value: unknown, opts: CliOptions = {}): void {\n log(`${c.bold(label)}: ${formatCell(value)}`, opts);\n}\n\n// ---------------------------------------------------------------------------\n// Spinner (stderr). ora when interactive; a no-op otherwise so scriptable /\n// CI / `--json` / `--quiet` runs pay nothing and never animate a pipe.\n// ---------------------------------------------------------------------------\nexport interface Spinner {\n start(text?: string): Spinner;\n stop(): Spinner;\n clear(): Spinner;\n succeed(text?: string): void;\n fail(text?: string): void;\n warn(text?: string): void;\n info(text?: string): void;\n text: string;\n}\n\nclass NoopSpinner implements Spinner {\n text = '';\n start(_text?: string): Spinner {\n return this;\n }\n stop(): Spinner {\n return this;\n }\n clear(): Spinner {\n return this;\n }\n succeed(_text?: string): void {}\n fail(_text?: string): void {}\n warn(_text?: string): void {}\n info(_text?: string): void {}\n}\n\n/** Wraps an `ora` instance so the `Spinner` interface stays decoupled from ora's exact type. */\nclass OraSpinner implements Spinner {\n private readonly handle: Ora;\n\n constructor(initialText: string) {\n this.handle = ora(initialText);\n }\n\n get text(): string {\n return this.handle.text;\n }\n set text(value: string) {\n this.handle.text = value;\n }\n\n start(text?: string): Spinner {\n if (text !== undefined) this.handle.text = text;\n this.handle.start();\n return this;\n }\n\n stop(): Spinner {\n this.handle.stop();\n return this;\n }\n\n clear(): Spinner {\n this.handle.clear();\n return this;\n }\n\n succeed(text?: string): void {\n this.handle.succeed(text);\n }\n\n fail(text?: string): void {\n this.handle.fail(text);\n }\n\n warn(text?: string): void {\n this.handle.warn(text);\n }\n\n info(text?: string): void {\n this.handle.info(text);\n }\n}\n\nexport function spinner(text = '', opts: CliOptions = {}): Spinner {\n if (isJsonMode(opts) || isQuietMode(opts) || !isInteractive(opts)) {\n return new NoopSpinner();\n }\n return new OraSpinner(text);\n}\n\n// ---------------------------------------------------------------------------\n// Failure + exit-code mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Write a diagnostic and throw a `CommanderError` carrying the S9 exit code,\n * so bin.ts's `exitOverride` + `handleError` surface it as `process.exitCode`\n * without any mid-action `process.exit`. Under `--json` the message becomes a\n * structured `{ok:false,error}` envelope on STDOUT; otherwise plain text on\n * STDERR. Always throws (`never`).\n */\nexport function fail(exitCode: number, message: string, opts: CliOptions = {}): never {\n if (isJsonMode(opts)) {\n process.stdout.write(`${JSON.stringify({ ok: false, error: { code: exitCode, message } })}\\n`);\n } else if (message.length > 0) {\n process.stderr.write(`${message}\\n`);\n }\n throw new CommanderError(exitCode, NOIR_ERROR_CODE, message);\n}\n\n/**\n * Guard for commands that would otherwise block on a prompt. Honors the S9\n * hard rule: \"no blocking prompts when !isTTY or --no-input — error exit 2\n * naming the missing flag instead\". `hint` describes the operation so the\n * message points the user at the flag-based alternative.\n */\nexport function requireInteractive(opts: CliOptions, hint: string): void {\n if (!isInteractive(opts)) {\n fail(\n EXIT.USAGE,\n `${hint} needs an interactive terminal, but input is disabled (non-TTY, --no-input, --json, CI, or NO_COLOR). Re-run in a TTY or supply the value as a flag.`,\n opts,\n );\n }\n}\n\n// Remap commander's own exit codes onto the S9 contract:\n// help/version → 0 · unknown command → 3 · every other usage error → 2\nfunction commanderExitCode(err: CommanderError): number {\n switch (err.code) {\n case 'commander.helpDisplayed':\n case 'commander.versionDisplayed':\n case 'commander.version': // commander v12 uses this code for --version (exit 0)\n return EXIT.OK;\n case 'commander.unknownCommand':\n return EXIT.NOT_FOUND;\n default:\n return EXIT.USAGE;\n }\n}\n\n/** Map any thrown value onto the S9 exit-code contract. */\nexport function inferExitCode(err: unknown): number {\n if (err instanceof NoirCliError) return err.exitCode;\n if (err instanceof CommanderError) {\n // Errors our own `fail()` threw carry a `noir.*` code and an authoritative\n // exitCode — respect it. Commander's own errors are remapped by `code`.\n if (err.code.startsWith('noir.')) return err.exitCode;\n return commanderExitCode(err);\n }\n return EXIT.ERROR;\n}\n\n/**\n * Map a thrown error onto stderr + `process.exitCode`. Never throws, never\n * calls `process.exit` (commander's `exitOverride` already prevented that for\n * commander's own errors). Used by the bin entry's `run()`.\n */\nexport function handleError(err: unknown): void {\n if (err instanceof NoirCliError) {\n if (err.message.length > 0) process.stderr.write(`${err.message}\\n`);\n } else if (err instanceof CommanderError) {\n // If `fail()` threw it, the message is already written (stderr or the JSON\n // stdout envelope); if commander threw it, `configureOutput.writeErr`\n // already wrote it during parse. Don't double-write either way.\n } else {\n process.stderr.write(`noir: ${err instanceof Error ? err.message : String(err)}\\n`);\n }\n process.exitCode = inferExitCode(err);\n}\n","// Single owner of the Noir CLI's semantic palette + status badges.\n//\n// Built on `picocolors` (the SAME lib the rest of the CLI already uses), so the\n// decoration strips consistently under NO_COLOR / non-TTY. cli-table3 styles\n// via a SECOND lib (@colors/colors) whose NO_COLOR/TTY semantics differ — that\n// split is what painted every table header red while the body stripped. Routing\n// ALL color through this module (the `c` object + `badge()`) closes that leak:\n// there is exactly one color authority, and it honors NO_COLOR / CLICOLOR_FORCE\n// / TTY uniformly.\n//\n// Accessibility:\n// - `badge()` ALWAYS returns SYMBOL + TEXT LABEL (e.g. `⚠ warn`), so NO_COLOR\n// and colorblind users get identical information. Color is decorative.\n// - `NOIR_ACCESSIBLE` disables the banner gradient (→ solid accent) and is the\n// documented opt-in for users who want the most legible form; badges already\n// carry symbol+text unconditionally, so the flag is a no-op for them.\n\nimport pc from 'picocolors';\n\n// A private always-on colorizer. The PUBLIC `c` object gates every call through\n// `useColor()`, so `useColor()` is the single live authority over whether ANY\n// ANSI leaves this module. (The default `picocolors` export captures its\n// `isColorSupported` snapshot once at module load and does NOT honor\n// CLICOLOR_FORCE; gating a forced instance here fixes both.)\nconst FORCE = pc.createColors(true);\n\n/** Badge state → semantic color role. */\nexport type BadgeState = 'ok' | 'warn' | 'error' | 'info';\n\n/**\n * The semantic palette. Each method returns its input unchanged when color is\n * off (NO_COLOR / non-TTY / not forced), so callers can wrap freely without\n * guarding. Compose with `c.bold(c.info(s))` etc.\n */\nexport const c = {\n /** Green — success / healthy. */\n ok: (s: string): string => (useColor() ? FORCE.green(s) : s),\n /** Yellow — degraded but usable. */\n warn: (s: string): string => (useColor() ? FORCE.yellow(s) : s),\n /** Red — reserved strictly for ERROR. Never a table header. */\n error: (s: string): string => (useColor() ? FORCE.red(s) : s),\n /** Cyan — informational / brand-neutral accent for labels. */\n info: (s: string): string => (useColor() ? FORCE.cyan(s) : s),\n /** Blue — the Midnight Cobalt brand role (banner / accent). */\n accent: (s: string): string => (useColor() ? FORCE.blue(s) : s),\n /** Dim — secondary text, table borders when color is on. */\n dim: (s: string): string => (useColor() ? FORCE.dim(s) : s),\n /** Bold — emphasis (table headers compose this with `info`). */\n bold: (s: string): string => (useColor() ? FORCE.bold(s) : s),\n};\n\n// @clack-style status symbols (the vocabulary Noir inherits via @clack/prompts\n// + ora). Paired 1:1 with a state name so a screen reader / pipe / colorblind\n// user reads the same fact a sighted interactive user sees.\nconst BADGE_SYMBOL: Readonly<Record<BadgeState, string>> = {\n ok: '✓',\n warn: '⚠',\n error: '✗',\n info: 'ℹ',\n};\n\n/**\n * Render a status badge: always `SYMBOL LABEL`, colored by `state` when color\n * is on. The TEXT LABEL is unconditional — this is the accessibility invariant.\n * `label` defaults to the state name, so `badge('ok')` reads `✓ ok`.\n *\n * @example badge('ok') // → green \"✓ ok\"\n * @example badge('warn','degraded') // → yellow \"⚠ degraded\"\n * @example badge('error','down') // → red \"✗ down\"\n */\nexport function badge(state: BadgeState, label: string = state): string {\n const text = `${BADGE_SYMBOL[state]} ${label}`;\n switch (state) {\n case 'ok':\n return c.ok(text);\n case 'warn':\n return c.warn(text);\n case 'error':\n return c.error(text);\n case 'info':\n return c.info(text);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Environment gates. Evaluated LIVE (not captured at module load) so tests that\n// flip NO_COLOR / CLICOLOR_FORCE between cases see the right answer, and so a\n// user exporting NO_COLOR mid-session is honored on the next render.\n// ---------------------------------------------------------------------------\n\nfunction envFlagSet(name: string): boolean {\n // NO_COLOR spec: present AND non-empty disables color (any value).\n const v = process.env[name];\n return v !== undefined && v !== '';\n}\n\n/**\n * True when running under a CI runner (GitHub Actions / GitLab / CircleCI /\n * Drone set `CI=true` at the conventional value). Treats the explicit opt-outs\n * `0` / `false` as \"not CI\" so a user can force-disable the guard. Owned here\n * (the color authority) and re-exported so output.ts doesn't duplicate it.\n */\nexport function isCiEnv(): boolean {\n const v = process.env.CI;\n if (v === undefined || v === '') return false;\n return v !== '0' && v !== 'false';\n}\n\n/**\n * The single authority on whether decoration should emit ANSI. Honors:\n * - `NO_COLOR` → always off (spec: present + non-empty).\n * - `CLICOLOR_FORCE=1` → always on (forces color on a redirected stream).\n * - `CI=true` (alone) → always OFF. picocolors' `isColorSupported`\n * snapshot turns color ON under `!!env.CI` (it\n * assumes a CI viewer that renders ANSI). But ANSI\n * escapes inflate the raw byte length of rendered\n * lines, which breaks the responsive-width\n * guarantee `max(line.length) <= terminalWidth()`\n * that `table()` exists to uphold — and the\n * regression test that locks it (fits 60/80/120 in\n * theme.test.ts). The CLI's own top-of-file\n * contract states decoration auto-disables under\n * CI / non-TTY; this honors that. A CI viewer that\n * wants color sets `CLICOLOR_FORCE=1` (above).\n * - otherwise → picocolors' detection (TTY / FORCE_COLOR).\n */\nexport function useColor(): boolean {\n if (envFlagSet('NO_COLOR')) return false;\n if (process.env.CLICOLOR_FORCE === '1') return true;\n if (isCiEnv()) return false;\n return pc.isColorSupported;\n}\n\n/**\n * `NOIR_ACCESSIBLE`: opt-in maximum legibility. Badges already carry symbol+\n * text unconditionally (so the flag is a no-op for them); the material effect\n * is disabling the banner gradient (→ solid accent) and is reserved here for\n * future accessible-display tweaks.\n */\nexport function accessibleMode(): boolean {\n return envFlagSet('NOIR_ACCESSIBLE');\n}\n\n/**\n * Terminal width in columns. Honors `COLUMNS` (the conventional override) then\n * `process.stdout.columns`, defaulting to 80 when neither is set (the same\n * default `picocolors` / `cli-table3` assume). Floored at a small minimum so a\n * misconfigured shell never produces a degenerate zero/negative-width table.\n */\nexport function terminalWidth(): number {\n const fromEnv = process.env.COLUMNS;\n if (fromEnv !== undefined && fromEnv !== '') {\n const n = Number(fromEnv);\n if (Number.isInteger(n) && n > 0) return Math.max(n, 20);\n }\n const cols = process.stdout.columns;\n if (typeof cols === 'number' && cols > 0) return Math.max(cols, 20);\n return 80;\n}\n"],"mappings":";;;;;;;;AAeA,OAAO,WAAW;AAClB,SAAS,sBAAsB;AAC/B,OAAO,SAAuB;;;ACA9B,OAAO,QAAQ;AAOf,IAAM,QAAQ,GAAG,aAAa,IAAI;AAU3B,IAAM,IAAI;AAAA;AAAA,EAEf,IAAI,CAAC,MAAuB,SAAS,IAAI,MAAM,MAAM,CAAC,IAAI;AAAA;AAAA,EAE1D,MAAM,CAAC,MAAuB,SAAS,IAAI,MAAM,OAAO,CAAC,IAAI;AAAA;AAAA,EAE7D,OAAO,CAAC,MAAuB,SAAS,IAAI,MAAM,IAAI,CAAC,IAAI;AAAA;AAAA,EAE3D,MAAM,CAAC,MAAuB,SAAS,IAAI,MAAM,KAAK,CAAC,IAAI;AAAA;AAAA,EAE3D,QAAQ,CAAC,MAAuB,SAAS,IAAI,MAAM,KAAK,CAAC,IAAI;AAAA;AAAA,EAE7D,KAAK,CAAC,MAAuB,SAAS,IAAI,MAAM,IAAI,CAAC,IAAI;AAAA;AAAA,EAEzD,MAAM,CAAC,MAAuB,SAAS,IAAI,MAAM,KAAK,CAAC,IAAI;AAC7D;AAKA,IAAM,eAAqD;AAAA,EACzD,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AACR;AAWO,SAAS,MAAM,OAAmB,QAAgB,OAAe;AACtE,QAAM,OAAO,GAAG,aAAa,KAAK,CAAC,IAAI,KAAK;AAC5C,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO,EAAE,GAAG,IAAI;AAAA,IAClB,KAAK;AACH,aAAO,EAAE,KAAK,IAAI;AAAA,IACpB,KAAK;AACH,aAAO,EAAE,MAAM,IAAI;AAAA,IACrB,KAAK;AACH,aAAO,EAAE,KAAK,IAAI;AAAA,EACtB;AACF;AAQA,SAAS,WAAW,MAAuB;AAEzC,QAAM,IAAI,QAAQ,IAAI,IAAI;AAC1B,SAAO,MAAM,UAAa,MAAM;AAClC;AAQO,SAAS,UAAmB;AACjC,QAAM,IAAI,QAAQ,IAAI;AACtB,MAAI,MAAM,UAAa,MAAM,GAAI,QAAO;AACxC,SAAO,MAAM,OAAO,MAAM;AAC5B;AAoBO,SAAS,WAAoB;AAClC,MAAI,WAAW,UAAU,EAAG,QAAO;AACnC,MAAI,QAAQ,IAAI,mBAAmB,IAAK,QAAO;AAC/C,MAAI,QAAQ,EAAG,QAAO;AACtB,SAAO,GAAG;AACZ;AAQO,SAAS,iBAA0B;AACxC,SAAO,WAAW,iBAAiB;AACrC;AAQO,SAAS,gBAAwB;AACtC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,YAAY,UAAa,YAAY,IAAI;AAC3C,UAAM,IAAI,OAAO,OAAO;AACxB,QAAI,OAAO,UAAU,CAAC,KAAK,IAAI,EAAG,QAAO,KAAK,IAAI,GAAG,EAAE;AAAA,EACzD;AACA,QAAM,OAAO,QAAQ,OAAO;AAC5B,MAAI,OAAO,SAAS,YAAY,OAAO,EAAG,QAAO,KAAK,IAAI,MAAM,EAAE;AAClE,SAAO;AACT;;;ADvIO,IAAM,OAAO;AAAA,EAClB,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,WAAW;AAAA,EACX,aAAa;AAAA,EACb,WAAW;AACb;AASO,IAAM,eAAN,cAA2B,MAAM;AAAA,EAC7B;AAAA,EACT,YAAY,UAAkB,SAAiB;AAC7C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AACF;AAQA,IAAM,kBAAkB;AA4BxB,SAAS,WAAW,MAA2B;AAC7C,SAAO,KAAK,SAAS;AACvB;AAEA,SAAS,YAAY,MAA2B;AAC9C,SAAO,KAAK,UAAU;AACxB;AAGO,SAAS,UAAU,OAAmB,CAAC,GAAY;AACxD,SAAO,KAAK,YAAY,QAAQ,KAAK,UAAU;AACjD;AAEA,SAASA,YAAW,MAAuB;AAEzC,QAAM,IAAI,QAAQ,IAAI,IAAI;AAC1B,SAAO,MAAM,UAAa,MAAM;AAClC;AASO,SAAS,cAAc,OAAmB,CAAC,GAAY;AAC5D,MAAI,WAAW,IAAI,KAAK,UAAU,IAAI,EAAG,QAAO;AAChD,MAAI,QAAQ,KAAKA,YAAW,UAAU,EAAG,QAAO;AAChD,SAAO,QAAQ,MAAM,UAAU,QAAQ,QAAQ,OAAO,UAAU;AAClE;AAUO,SAAS,qBAA8B;AAC5C,MAAI,yBAAyB,EAAG,QAAO;AACvC,SAAO,cAAc;AACvB;AAKA,SAAS,2BAAoC;AAC3C,QAAM,IAAI,QAAQ,IAAI;AACtB,SAAO,MAAM,UAAa,MAAM;AAClC;AAOO,SAAS,KAAK,KAAoB;AACvC,UAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,GAAG,CAAC;AAAA,CAAI;AACjD;AAQO,SAAS,IAAI,KAAa,OAAmB,CAAC,GAAS;AAC5D,MAAI,WAAW,IAAI,KAAK,YAAY,IAAI,EAAG;AAC3C,UAAQ,OAAO,MAAM,GAAG,GAAG;AAAA,CAAI;AACjC;AAEO,SAAS,KAAK,KAAa,OAAmB,CAAC,GAAS;AAC7D,MAAI,WAAW,IAAI,KAAK,YAAY,IAAI,EAAG;AAC3C,UAAQ,OAAO,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,CAAI;AACzC;AAEO,SAAS,QAAQ,KAAa,OAAmB,CAAC,GAAS;AAChE,MAAI,WAAW,IAAI,KAAK,YAAY,IAAI,EAAG;AAC3C,UAAQ,OAAO,MAAM,GAAG,EAAE,GAAG,GAAG,CAAC;AAAA,CAAI;AACvC;AAEO,SAAS,KAAK,KAAa,OAAmB,CAAC,GAAS;AAC7D,MAAI,WAAW,IAAI,EAAG;AACtB,UAAQ,OAAO,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,CAAI;AACzC;AAEO,SAAS,MAAM,KAAa,OAAmB,CAAC,GAAS;AAC9D,MAAI,WAAW,IAAI,EAAG;AACtB,UAAQ,OAAO,MAAM,GAAG,EAAE,MAAM,GAAG,CAAC;AAAA,CAAI;AAC1C;AASO,SAAS,IAAI,KAAa,OAAmB,CAAC,GAAS;AAC5D,MAAI,WAAW,IAAI,KAAK,KAAK,WAAW,KAAM;AAC9C,UAAQ,OAAO,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,CAAI;AACzC;AAiBO,SAAS,MACd,MACA,MACA,OAAmB,CAAC,GACd;AACN,MAAI,WAAW,IAAI,EAAG;AACtB,MAAI,KAAK,WAAW,GAAG;AACrB,SAAK,aAAa,IAAI;AACtB;AAAA,EACF;AACA,QAAM,IAAI,IAAI,MAAM;AAAA,IAClB,MAAM,KAAK,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;AAAA;AAAA;AAAA,IAG3C,OAAO,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,EAAE;AAAA,IAC9B,WAAW,iBAAiB,MAAM,IAAI;AAAA,IACtC,UAAU;AAAA,IACV,UAAU;AAAA,EACZ,CAAC;AACD,aAAW,OAAO,MAAM;AACtB,MAAE,KAAK,KAAK,IAAI,CAAC,QAAQ,WAAW,IAAI,GAAG,CAAC,CAAC,CAAC;AAAA,EAChD;AACA,UAAQ,OAAO,MAAM,GAAG,EAAE,SAAS,CAAC;AAAA,CAAI;AAC1C;AAmBA,SAAS,iBACP,MACA,MACU;AACV,QAAM,IAAI,KAAK;AACf,MAAI,MAAM,EAAG,QAAO,CAAC;AACrB,QAAM,YAAY,KAAK,IAAI,CAAC,QAAQ,IAAI,MAAM;AAC9C,QAAM,UAAU,KAAK,IAAI,CAAC,KAAK,MAAM;AACnC,QAAI,MAAM,KAAK,IAAI,UAAU,CAAC,KAAK,IAAI,QAAQ,CAAC;AAChD,eAAW,OAAO,MAAM;AACtB,YAAM,MAAM,WAAW,IAAI,GAAG,CAAC,EAAE;AACjC,UAAI,MAAM,IAAK,OAAM;AAAA,IACvB;AACA,WAAO;AAAA,EACT,CAAC;AAID,QAAM,gBAAgB,KAAK,IAAI,IAAI,GAAG,cAAc,IAAI,IAAI,IAAI,CAAC;AACjE,QAAM,aAAa,QAAQ,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AACpD,MAAI,cAAc,eAAe;AAC/B,WAAO,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC;AAAA,EACjC;AAEA,QAAM,UAAU,QAAQ,MAAM;AAC9B,MAAI,MAAM;AACV,QAAM,QAAQ,UAAU,IAAI,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,CAAC;AACjD,SAAO,MAAM,eAAe;AAC1B,QAAI,MAAM;AACV,QAAI,SAAS;AACb,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAMC,KAAI,QAAQ,CAAC,KAAK;AACxB,YAAM,IAAI,MAAM,CAAC,KAAK;AACtB,UAAIA,KAAI,KAAKA,KAAI,QAAQ;AACvB,iBAASA;AACT,cAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI,QAAQ,GAAI;AAChB,UAAM,YAAY,MAAM;AACxB,UAAM,aAAa,QAAQ,GAAG,KAAK,MAAM,MAAM,GAAG,KAAK;AACvD,UAAM,MAAM,KAAK,IAAI,WAAW,SAAS;AACzC,YAAQ,GAAG,KAAK,QAAQ,GAAG,KAAK,KAAK;AACrC,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC;AACjC;AAEA,SAAS,WAAW,OAAwB;AAC1C,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,aAAa,OAAO,UAAU,UAAU;AACxF,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,SAAO,KAAK,UAAU,KAAK;AAC7B;AAeO,SAAS,eAAe,MAAgC,OAAmB,CAAC,GAAS;AAC1F;AAAA,IACE,KAAK,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,OAAO,WAAW,EAAE,KAAK,EAAE,EAAE;AAAA,IAChE,CAAC,SAAS,OAAO;AAAA,IACjB;AAAA,EACF;AACF;AAyGO,SAAS,KAAK,UAAkB,SAAiB,OAAmB,CAAC,GAAU;AACpF,MAAI,WAAW,IAAI,GAAG;AACpB,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,UAAU,QAAQ,EAAE,CAAC,CAAC;AAAA,CAAI;AAAA,EAC/F,WAAW,QAAQ,SAAS,GAAG;AAC7B,YAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAAA,EACrC;AACA,QAAM,IAAI,eAAe,UAAU,iBAAiB,OAAO;AAC7D;AAQO,SAAS,mBAAmB,MAAkB,MAAoB;AACvE,MAAI,CAAC,cAAc,IAAI,GAAG;AACxB;AAAA,MACE,KAAK;AAAA,MACL,GAAG,IAAI;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;AAIA,SAAS,kBAAkB,KAA6B;AACtD,UAAQ,IAAI,MAAM;AAAA,IAChB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,KAAK;AAAA,IACd,KAAK;AACH,aAAO,KAAK;AAAA,IACd;AACE,aAAO,KAAK;AAAA,EAChB;AACF;AAGO,SAAS,cAAc,KAAsB;AAClD,MAAI,eAAe,aAAc,QAAO,IAAI;AAC5C,MAAI,eAAe,gBAAgB;AAGjC,QAAI,IAAI,KAAK,WAAW,OAAO,EAAG,QAAO,IAAI;AAC7C,WAAO,kBAAkB,GAAG;AAAA,EAC9B;AACA,SAAO,KAAK;AACd;AAOO,SAAS,YAAY,KAAoB;AAC9C,MAAI,eAAe,cAAc;AAC/B,QAAI,IAAI,QAAQ,SAAS,EAAG,SAAQ,OAAO,MAAM,GAAG,IAAI,OAAO;AAAA,CAAI;AAAA,EACrE,WAAW,eAAe,gBAAgB;AAAA,EAI1C,OAAO;AACL,YAAQ,OAAO,MAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AAAA,EACpF;AACA,UAAQ,WAAW,cAAc,GAAG;AACtC;","names":["envFlagSet","c"]}
@@ -1,8 +1,10 @@
1
1
  import {
2
2
  buildConflictOpts,
3
- checkWritePathDedup,
3
+ checkWritePathDedup
4
+ } from "./chunk-BDFQ5S3K.js";
5
+ import {
4
6
  resolveInteractive
5
- } from "./chunk-YNEBQJXA.js";
7
+ } from "./chunk-L5ZKEOQV.js";
6
8
 
7
9
  // src/init.ts
8
10
  import { resolveAdapter } from "@noir-ai/adapters";
@@ -96,4 +98,4 @@ export {
96
98
  init,
97
99
  assertTransportUrl
98
100
  };
99
- //# sourceMappingURL=chunk-OMF7XZMN.js.map
101
+ //# sourceMappingURL=chunk-LHT7M6DO.js.map