{"_id":"@agentine/spectra","name":"@agentine/spectra","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@agentine/spectra","version":"0.1.0","description":"A unified, zero-dependency terminal styling library that replaces the fragmented chalk ecosystem.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./styles":{"types":"./dist/styles.d.ts","import":"./dist/styles.js"},"./detect":{"types":"./dist/detect.d.ts","import":"./dist/detect.js"},"./strip":{"types":"./dist/strip.d.ts","import":"./dist/strip.js"},"./wrap":{"types":"./dist/wrap.d.ts","import":"./dist/wrap.js"},"./convert":{"types":"./dist/convert.d.ts","import":"./dist/convert.js"}},"scripts":{"build":"tsc","test":"vitest run","test:watch":"vitest","bench":"vitest bench"},"keywords":["terminal","color","ansi","chalk","style","styling","cli"],"license":"MIT","devDependencies":{"@types/jscodeshift":"^17.3.0","@types/node":"^25.4.0","chalk":"^5.6.2","jscodeshift":"^17.3.0","picocolors":"^1.1.1","typescript":"^5.7.0","vitest":"^3.0.0","yoctocolors":"^2.1.2"},"gitHead":"1250a00b23c905c4bcd783449ecc8cc5718dc8ef","_id":"@agentine/spectra@0.1.0","_nodeVersion":"25.6.1","_npmVersion":"11.9.0","dist":{"integrity":"sha512-Y2DY7It633ELh5r1b/slWvtY2D+jXjhEJ55tpxxvgNTmzd1eWbOPN7rSIRHiM6eXYXrEaStpzF8/gTir37HnUw==","shasum":"65799a60c3235479b724dec965f348df7a339fab","tarball":"https://registry.npmjs.org/@agentine/spectra/-/spectra-0.1.0.tgz","fileCount":31,"unpackedSize":120004,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAIKQjV5g0SgfFQ+yzM5IzkgcnJB98EMm1rEXIgbgaA/AiEAlVc2ygCgww8sAgPFWSd2oIanasEhOTAF0nQoN1QrmBs="}]},"_npmUser":{"name":"mtingers","email":"matthingersoll@gmail.com"},"directories":{},"maintainers":[{"name":"mtingers","email":"matthingersoll@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/spectra_0.1.0_1773204292405_0.28234826874170094"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-11T04:44:52.343Z","0.1.0":"2026-03-11T04:44:52.545Z","modified":"2026-03-11T04:44:52.715Z"},"maintainers":[{"name":"mtingers","email":"matthingersoll@gmail.com"}],"description":"A unified, zero-dependency terminal styling library that replaces the fragmented chalk ecosystem.","keywords":["terminal","color","ansi","chalk","style","styling","cli"],"license":"MIT","readme":"# spectra\n\nA unified, zero-dependency terminal styling library that replaces the fragmented chalk ecosystem.\n\nOne package. One audit surface. Full chalk compatibility.\n\n## Why spectra?\n\nThe chalk ecosystem spans 15+ interdependent packages collectively downloaded **2 billion+ times per week**, maintained by 1-2 individuals. In September 2025, a single phished maintainer credential compromised 18 packages simultaneously, injecting crypto-stealing code into millions of installs.\n\n**spectra consolidates the entire chalk stack into a single zero-dependency package:**\n\n| What you get | What it replaces |\n|---|---|\n| `spectra` (main API) | `chalk`, `ansi-styles` |\n| `spectra/strip` | `strip-ansi`, `ansi-regex`, `has-ansi` |\n| `spectra/detect` | `supports-color`, `supports-hyperlinks` |\n| `spectra/wrap` | `wrap-ansi`, `slice-ansi` |\n| `spectra/convert` | `color-convert`, `color-name` |\n\nOne codebase, one publish pipeline, one audit surface. The security benefit alone justifies the switch.\n\n## Install\n\n```sh\nnpm install spectra\n```\n\n## Quick start\n\n```typescript\nimport spectra from 'spectra';\n\n// Basic styling\nspectra.red('Error!');\nspectra.bold.green('Success!');\nspectra.yellow.underline('Warning');\n\n// Hex, RGB, HSL colors\nspectra.hex('#ff6600')('Orange text');\nspectra.rgb(255, 136, 0).bold('Also orange');\nspectra.hsl(32, 100, 50)('Still orange');\n\n// Background colors\nspectra.bgRed.white.bold(' ERROR ');\nspectra.bgHex('#663399')(' Purple background ');\n\n// Nesting\nspectra.red(`Error: ${spectra.bold('critical')} failure`);\n\n// Template syntax\nspectra.template('{red Error:} {bold.yellow critical} failure');\n```\n\n## API Reference\n\n### Main API\n\n```typescript\nimport spectra from 'spectra';\n```\n\n#### Modifiers\n\n`reset`, `bold`, `dim`, `italic`, `underline`, `inverse`, `hidden`, `strikethrough`, `overline`\n\n```typescript\nspectra.bold('Bold text');\nspectra.italic.dim('Subtle');\n```\n\n#### Colors\n\n**Foreground:** `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`\n\n**Bright variants:** `blackBright`, `redBright`, `greenBright`, `yellowBright`, `blueBright`, `magentaBright`, `cyanBright`, `whiteBright`\n\n**Aliases:** `gray`/`grey` (same as `blackBright`)\n\n**Background:** All foreground colors are available as `bg*` variants — `bgRed`, `bgGreen`, `bgBlue`, `bgYellow`, `bgMagenta`, `bgCyan`, `bgWhite`, `bgBlack`, plus bright variants (`bgRedBright`, etc.) and aliases (`bgGray`/`bgGrey`).\n\n```typescript\nspectra.red.bgWhite('Red on white');\nspectra.bgBlue.whiteBright.bold('Bold white on blue');\n```\n\n#### Chaining\n\nAll styles are chainable. Each property returns a new spectra instance with the added style:\n\n```typescript\nspectra.red.bold.underline('Styled text');\nspectra.bgYellow.black.italic('Warning');\n```\n\n#### Dynamic colors\n\n```typescript\n// Foreground\nspectra.hex('#ff6600')('Hex color');\nspectra.hex('ff6600')('Also works without #');\nspectra.rgb(255, 136, 0)('RGB color');\nspectra.hsl(32, 100, 50)('HSL color');\nspectra.hsv(32, 100, 100)('HSV color');\nspectra.hwb(32, 0, 0)('HWB color');\nspectra.ansi256(202)('256-color');\n\n// Background\nspectra.bgHex('#663399')('Hex background');\nspectra.bgRgb(102, 51, 153)('RGB background');\nspectra.bgHsl(270, 50, 40)('HSL background');\nspectra.bgHsv(270, 67, 60)('HSV background');\nspectra.bgHwb(270, 20, 40)('HWB background');\nspectra.bgAnsi256(93)('256-color background');\n```\n\nDynamic colors chain with static styles:\n\n```typescript\nspectra.hex('#ff6600').bold.underline('Orange, bold, underlined');\n```\n\n#### Template syntax\n\n```typescript\nspectra.template('{red Error:} {bold.yellow critical} failure');\nspectra.template('{green.bold Success!} Operation complete.');\nspectra.template('{bgRed.white  FAIL } Test did not pass.');\n```\n\nStyles are dot-separated within the braces. The content follows after a space.\n\n#### Color level\n\nspectra auto-detects your terminal's color support. You can override it:\n\n```typescript\nspectra.level = 0; // No colors (strips all styling)\nspectra.level = 1; // Basic 16 colors\nspectra.level = 2; // 256 colors\nspectra.level = 3; // Truecolor (16 million colors)\n```\n\nColors are automatically downgraded to match the terminal's capability. For example, `spectra.hex('#ff6600')` on a level 1 terminal emits the nearest basic ANSI color.\n\n### spectra/strip\n\nStrip, detect, and match ANSI escape codes.\n\n```typescript\nimport { strip, hasAnsi, ansiRegex } from 'spectra/strip';\n\nstrip('\\x1b[31mhello\\x1b[39m');   // 'hello'\nhasAnsi('\\x1b[31mhello\\x1b[39m'); // true\nhasAnsi('plain text');             // false\n\nconst regex = ansiRegex();         // RegExp matching all ANSI sequences\n```\n\nHandles CSI sequences (colors/styles), OSC sequences (hyperlinks, terminal titles), and single-character escape sequences.\n\n### spectra/detect\n\nDetect terminal color support and hyperlink capability.\n\n```typescript\nimport { detectColors, colorLevel, supportsHyperlinks } from 'spectra/detect';\n\ndetectColors();\n// { level: 3, has256: true, has16m: true }\n\ncolorLevel(process.stdout);\n// 0 | 1 | 2 | 3\n\nsupportsHyperlinks(process.stdout);\n// true | false\n```\n\nDetection respects `FORCE_COLOR`, `NO_COLOR`, `--no-color`, `--color`, `COLORTERM`, and `TERM` environment variables. It recognizes Windows Terminal, iTerm, Apple Terminal, VS Code, WezTerm, CI providers (GitHub Actions, Travis, CircleCI, GitLab CI, etc.), and standard terminal emulators.\n\n### spectra/wrap\n\nANSI-aware word wrapping, slicing, and truncation.\n\n```typescript\nimport { wrapAnsi, sliceAnsi, truncateAnsi } from 'spectra/wrap';\n\n// Word-wrap at column 40, preserving ANSI styles across line breaks\nwrapAnsi(styledString, 40);\n\n// Options\nwrapAnsi(styledString, 40, {\n  hard: true,       // Break words longer than column width (default: false)\n  trim: false,      // Keep leading whitespace on wrapped lines (default: true)\n  wordWrap: false,  // Disable word wrapping, only break at column (default: true)\n});\n\n// Slice by visible character position, preserving ANSI state\nsliceAnsi(styledString, 5, 15);\n\n// Truncate with optional ellipsis\ntruncateAnsi(styledString, 20, '…');\n```\n\n### spectra/convert\n\nConvert between color spaces. Replaces the `color-convert` and `color-name` packages.\n\n```typescript\nimport { convert } from 'spectra/convert';\n\n// Structured API: convert.<from>.<to>(values)\nconvert.rgb.hsl(255, 136, 0);     // [32, 100, 50]\nconvert.rgb.hsv(255, 136, 0);     // [32, 100, 100]\nconvert.rgb.hwb(255, 136, 0);     // [32, 0, 0]\nconvert.rgb.cmyk(255, 136, 0);    // [0, 47, 100, 0]\nconvert.rgb.hex(255, 136, 0);     // '#ff8800'\nconvert.rgb.ansi256(255, 136, 0); // 214\nconvert.rgb.ansi16(255, 136, 0);  // 93\n\nconvert.hsl.rgb(32, 100, 50);     // [255, 136, 0]\nconvert.hsv.rgb(32, 100, 100);    // [255, 136, 0]\nconvert.hwb.rgb(32, 0, 0);        // [255, 136, 0]\nconvert.cmyk.rgb(0, 47, 100, 0);  // [255, 135, 0]\nconvert.hex.rgb('#ff8800');        // [255, 136, 0]\nconvert.ansi256.rgb(214);         // [255, 175, 0]\nconvert.ansi16.rgb(93);           // [255, 255, 0]\nconvert.keyword.rgb('tomato');     // [255, 99, 71]\n```\n\nAll 148 CSS Color Level 4 named colors are supported via `convert.keyword.rgb()`.\n\nIndividual conversion functions are also exported for direct use:\n\n```typescript\nimport { rgbToHsl, hslToRgb, hexToRgb, rgbToHex } from 'spectra/convert';\n\nrgbToHsl(255, 136, 0);  // [32, 100, 50]\nhslToRgb(32, 100, 50);  // [255, 136, 0]\n```\n\n## Migration from chalk\n\n### Step 1: Install spectra\n\n```sh\nnpm install spectra\nnpm uninstall chalk ansi-styles supports-color strip-ansi ansi-regex has-ansi wrap-ansi slice-ansi color-convert color-name\n```\n\n### Step 2: Update imports\n\nFor most projects, find and replace is all you need:\n\n```diff\n- import chalk from 'chalk';\n+ import spectra from 'spectra';\n\n- chalk.red.bold('Error!')\n+ spectra.red.bold('Error!')\n```\n\nThe API is designed so that `s/chalk/spectra/g` works for the main styling API.\n\nFor subpackages:\n\n```diff\n- import stripAnsi from 'strip-ansi';\n- import { supportsColor } from 'supports-color';\n- import wrapAnsi from 'wrap-ansi';\n- import colorConvert from 'color-convert';\n+ import { strip } from 'spectra/strip';\n+ import { detectColors } from 'spectra/detect';\n+ import { wrapAnsi } from 'spectra/wrap';\n+ import { convert } from 'spectra/convert';\n```\n\n### Step 3: Automated migration (optional)\n\nA jscodeshift codemod is included for automated migration:\n\n```sh\nnpx jscodeshift -t node_modules/spectra/codemods/chalk-to-spectra.ts --parser=tsx src/\n```\n\nThe codemod handles:\n- Default, named, and namespace ESM imports\n- CommonJS `require()` calls\n- Subpath mapping (`chalk/ansi-styles` -> `spectra/styles`, `chalk/supports-color` -> `spectra/detect`)\n- Renaming all `chalk` identifier references to `spectra`\n\n### API equivalents\n\n| chalk ecosystem | spectra |\n|---|---|\n| `chalk.red('text')` | `spectra.red('text')` |\n| `chalk.hex('#ff6600')('text')` | `spectra.hex('#ff6600')('text')` |\n| `chalk.rgb(255, 136, 0)('text')` | `spectra.rgb(255, 136, 0)('text')` |\n| `chalk.level` | `spectra.level` |\n| `stripAnsi(str)` | `strip(str)` from `spectra/strip` |\n| `hasAnsi(str)` | `hasAnsi(str)` from `spectra/strip` |\n| `ansiRegex()` | `ansiRegex()` from `spectra/strip` |\n| `supportsColor.stdout` | `detectColors(process.stdout)` from `spectra/detect` |\n| `wrapAnsi(str, cols)` | `wrapAnsi(str, cols)` from `spectra/wrap` |\n| `colorConvert.rgb.hsl(r, g, b)` | `convert.rgb.hsl(r, g, b)` from `spectra/convert` |\n| `colorName['tomato']` | `convert.keyword.rgb('tomato')` from `spectra/convert` |\n\n### Known differences\n\n- **ESM only.** spectra ships as ESM. If you need CJS, use dynamic `import()` or a bundler.\n- **`supports-color` return shape.** chalk's `supports-color` returns `{ stdout: { level, hasBasic, has256, has16m } }`. spectra's `detectColors()` returns `{ level, has256, has16m }` directly — pass the stream as an argument instead.\n- **Template syntax.** spectra's `spectra.template()` is a method, not a tagged template literal.\n\n## Environment variables\n\n| Variable | Effect |\n|---|---|\n| `FORCE_COLOR=0\\|1\\|2\\|3` | Force a specific color level |\n| `FORCE_COLOR=true` | Force level 1 |\n| `FORCE_COLOR=false` | Disable colors |\n| `NO_COLOR` | Disable colors ([no-color.org](https://no-color.org)) |\n| `COLORTERM=truecolor` | Signal truecolor support |\n| `FORCE_HYPERLINK=1` | Force hyperlink support detection |\n\nCLI flags `--color` and `--no-color` are also respected.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-f5b45d8037fe2aba6e2c5c07cf525da2"}