npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sprucelabs/spruce-skill-utils

v34.0.25

Published

Loosely coupled classes and functions to make skill development faster! 🏎

Downloads

17,827

Readme

Spruce Skill Utils

Utilities and services used across Spruce skills and tooling. Exports are available from src/index.ts.

Utilities

buildLog (Logging)

Structured logger with prefixes, transports, time decorations, log gating, and history tracking.

Quick start

import buildLog from '@sprucelabs/spruce-skill-utils'

const log = buildLog('APP', { useColors: false })
log.info('booting')
log.warn('cache miss', { key: 'users:1' })
log.error('boom', new Error('Something failed'))

Prefixes and hierarchy

Prefixes are chained via buildLog. Returned strings include the prefixes, and transports receive the prefix as a separate first argument.

const root = buildLog('ROOT', { useColors: false })

root.info('message')

const child = root.buildLog('CHILD')
child.error('an error occurred')

Outputs:

  1. (INFO) ROOT :: message
  2. (ERROR) ROOT :: CHILD :: an error occurred

Maximum prefix length

Use MAXIMUM_LOG_PREFIXES_LENGTH to limit how many prefix segments are included.

process.env.MAXIMUM_LOG_PREFIXES_LENGTH = '2'

const log = buildLog('ONE')
  .buildLog('TWO')
  .buildLog('THREE')

log.info('value')

Transport receives: TWO :: THREE :: value

Set to 0 to suppress prefixes entirely.

Log level gating

Control which levels are emitted using LOG_LEVEL.

process.env.LOG_LEVEL = 'warn'

const log = buildLog('APP', { useColors: false })

log.info('info message')
log.warn('warn message')
log.error('error message')

With LOG_LEVEL=warn, only warn and error are emitted.

Time decorations

By default, log output includes a timestamp and a time-since-last-log delta. Disable with env flags.

process.env.SHOULD_LOG_TIME = 'false'
process.env.SHOULD_LOG_TIME_DELTAS = 'false'

const log = buildLog('TIMESTAMPS', { useColors: false })
log.info('first')

Transports

You can route logs per level to custom transports. Transports receive prefix and args only (no (INFO) or timestamps).

let infoMessage = ''
let errorMessage = ''

const log = buildLog('TEST', {
  useColors: false,
  transportsByLevel: {
    INFO: (...parts) => { infoMessage = parts.join(' ') },
    ERROR: (...parts) => { errorMessage = parts.join(' ') },
  },
})

log.info('go team')
log.error('error me')

Captured values:

  1. infoMessage becomes TEST :: go team
  2. errorMessage becomes TEST :: error me

You can also provide multiple transports per level:

const log = buildLog('MULTI', {
  transportsByLevel: {
    INFO: [
      (...parts) => console.log('one', parts.join(' ')),
      (...parts) => console.log('two', parts.join(' ')),
    ],
  },
})

Custom log override (rare)

If you provide log, it overrides the output target entirely (no console/stderr). This is typically only useful in tests.

const log = buildLog('NOOP', { useColors: false, log: () => {} })

log.info('this returns a string, but nothing is emitted')

Colors and TTY

Colors are enabled only when stdout.isTTY is true and useColors !== false.

process.stdout.isTTY = false
const log = buildLog('TTY', {})
log.info('go team')

Output: (INFO) TTY :: go team

Prefix-based logging control

If isMainModule() is false, logging is disabled unless SPRUCE_LOGS includes the logger’s prefix.

process.env.SPRUCE_LOGS = 'Billing,Auth'
const log = buildLog('Auth', { useColors: false })
log.info('allowed')

History tracking

Logging history is shared across all logger instances.

const log = buildLog()
log.startTrackingHistory(2)

log.info('one')
log.info('two')
log.info('three')

log.getHistory()

History contains: ["two", "three"]

API

  1. buildLog(prefix?: string, options?: LogOptions): Log
  2. Logger class (implements Log)
  3. testLog and stubLog

testLog

Logger preconfigured to write to stderr. Useful in tests.

stubLog

Logger preconfigured to do nothing. Colors disabled.

diskUtil

Filesystem helper utilities.

Key behaviors

  1. resolvePath resolves relative paths to a cwd and expands #spruce to .spruce.
  2. resolveFile searches for bare, .js, and .ts files in order.
  3. hasFileChanged tracks file changes using .change_cache and a .gitignore in that cache directory.
  4. deleteEmptyDirs removes empty directories recursively and validates inputs.
  5. detectProjectLanguage infers ts, js, go, or unknown.

versionUtil

Versioned-path helper that works with vYYYY_MM_DD directories and {{@latest}} tokens.

Key behaviors

  1. resolvePath replaces {{@latest}} with the latest version directory.
  2. resolveNewLatestPath creates a new latest path using today’s date.
  3. getAllVersions returns sorted version metadata.
  4. latestVersionAtPath throws if no versioning exists.

namesUtil

String and naming helpers.

API

  1. toFileNameWithoutExtension
  2. toCamel
  3. toPascal
  4. toConst
  5. toPlural
  6. toSingular
  7. toKebab
  8. toSnake

addonUtil

Discovers and loads *.addon.[t|j]s files.

Key behaviors

  1. import loads all addons under a path and awaits results.
  2. importSync loads all addons synchronously.
  3. If a module has a default export function, it is invoked with options.

pluginUtil

Discovers and loads *.plugin.[t|j]s files.

Key behaviors

  1. import loads plugins asynchronously and returns their results.
  2. importSync loads plugins synchronously and validates inputs.
  3. Plugins must export a default function or an error is thrown.

randomUtil

Random selection helper.

API

  1. rand<T>(possibilities: T[]): T

joinIntoSentence

Joins words into a human-readable sentence with an & before the last item.

Example

  1. ['hey', 'there']hey & there
  2. ['a', 'b', 'c']a, b & c

slug

Creates a lowercase, dash-separated slug from an input string.

cloneDeep

Deprecated wrapper around @sprucelabs/schema cloneDeep. Prefer importing directly from @sprucelabs/schema.

isEqual

Deep equality check with special handling for Date and with null/undefined field removal.

Renderers

locationRenderer

Renders an AddressFieldValue into a single, trimmed line with missing fields omitted.

Services

SettingsService

Persists feature flags and settings to a JSON file under .spruce.

Key behaviors

  1. Supports markAsInstalled and markAsPermanentlySkipped.
  2. Supports nested get, set, and unset.
  3. Uses .spruce/settings.json for JS/TS projects and .spruce/settings.json in the repo root for Go projects.
  4. Supports custom settings filename via setFile.

EnvService

Reads and writes a .env file in the current working directory.

Key behaviors

  1. set writes literals with quoting and escapes newlines.
  2. get coerces booleans and integers.
  3. unset removes keys from both the file and process.env.

PkgService

Reads and writes package.json.

Key behaviors

  1. get, set, and unset for package fields.
  2. doesExist checks for package.json.
  3. isInstalled checks dependencies and devDependencies.
  4. deleteLockFile removes package-lock.json and yarn.lock.
  5. buildPackageName formats name@version.

AuthService

Manages local auth state for skills.

Key behaviors

  1. Auth(cwd) validates a package.json exists and returns a service instance.
  2. Persists a logged-in person to ~/.spruce/person.json.
  3. Reads and updates current skill credentials from .env and package.json.
  4. Normalizes and validates person data against a schema.

Types and constants

Exports include Skill, SkillAuth, PersonWithToken, EnvValue, and constants such as HASH_SPRUCE_DIR, LATEST_HANDLEBARS, and CORE_SCHEMA_VERSION.