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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@kodebase/artifacts

v1.1.3

Published

High-level artifact operations for Kodebase

Readme

@kodebase/artifacts

npm version npm downloads CI status

High-level artifact operations for Kodebase. Provides CRUD services, tree traversal, dependency graph analysis, readiness validation, query filtering, and user-friendly error formatting for Initiatives, Milestones, and Issues.

Overview

@kodebase/artifacts is a service layer built on top of @kodebase/core that provides high-level operations for managing Kodebase artifacts. While @kodebase/core handles low-level parsing, validation, and I/O, this package orchestrates complex workflows like ID allocation, scaffolding, tree traversal, dependency resolution, and readiness checks.

Architecture

┌──────────────────────────────────────────────────┐
│                  CLI / Web UI                    │
│         (@kodebase/cli, custom tools)            │
└──────────────────────────────────────────────────┘
                        │
                        ▼
┌──────────────────────────────────────────────────┐
│            @kodebase/artifacts                   │
│  • ArtifactService (CRUD operations)             │
│  • QueryService (tree traversal, filtering)      │
│  • DependencyGraphService (graph analysis)       │
│  • ReadinessService (workflow validation)        │
│  • ValidationService (orchestrated checks)       │
│  • ScaffoldingService (artifact creation)        │
│  • IdAllocationService (unique ID generation)    │
│  • ContextService (project detection)            │
└──────────────────────────────────────────────────┘
                        │
                        ▼
┌──────────────────────────────────────────────────┐
│              @kodebase/core                      │
│  • Schemas (Zod validation)                      │
│  • Parser (YAML ↔ TypeScript)                    │
│  • State Machine (lifecycle transitions)         │
│  • I/O (file read/write)                         │
│  • Cascade Engine (automation)                   │
└──────────────────────────────────────────────────┘

When to Use This Package

Use @kodebase/artifacts when you need:

  • High-level operations: Creating, reading, updating artifacts with automatic path resolution
  • Complex queries: Tree traversal, filtering by state/assignee/priority
  • Workflow validation: Dependency checking, readiness validation, state transitions
  • ID management: Auto-allocating sequential IDs, slug generation
  • Developer experience: User-friendly error messages, CLI-ready formatting

Use @kodebase/core directly when you need:

  • Low-level control: Custom validation logic, manual YAML parsing
  • Building blocks: Implementing your own service layer
  • Performance: Skipping service layer overhead for batch operations

Installation

pnpm add @kodebase/artifacts
# or
npm install @kodebase/artifacts

Dependencies: This package requires @kodebase/core which is automatically installed as a dependency.

Public API

ArtifactService

High-level service for artifact CRUD operations with automatic directory structure handling.

import { ArtifactService } from "@kodebase/artifacts";
import { scaffoldInitiative } from "@kodebase/core";

const service = new ArtifactService();

// Create an artifact
const initiative = scaffoldInitiative({
  title: "New Initiative",
  createdBy: "Alice ([email protected])",
  vision: "Build something great",
  scopeIn: ["Feature A"],
  scopeOut: ["Feature B"],
  successCriteria: ["All tests pass"]
});

const filePath = await service.createArtifact({
  id: "A",
  artifact: initiative,
  slug: "new-initiative"
});

// Get an artifact
const artifact = await service.getArtifact({
  id: "A",
  slug: "new-initiative"
});

// Update metadata
const updated = await service.updateMetadata({
  id: "A",
  updates: {
    priority: CPriority.HIGH,
    title: "Updated Title"
  }
});

// Append an event
const withEvent = await service.appendEvent({
  id: "A",
  event: {
    event: "ready",
    timestamp: "2025-11-02T12:00:00Z",
    actor: "Alice ([email protected])",
    trigger: CEventTrigger.DEPENDENCIES_MET
  }
});

Methods:

  • createArtifact(options) - Creates artifact with proper directory structure
  • getArtifact(options) - Retrieves artifact by ID and optional slug
  • updateMetadata(options) - Updates metadata while preserving events
  • appendEvent(options) - Appends new event to events array

Throws:

  • ArtifactNotFoundError - When artifact file doesn't exist

QueryService

Query and traverse the artifact tree with filtering, tree operations, and dependency graph support.

import { QueryService } from "@kodebase/artifacts";

const service = new QueryService();

// Tree traversal
const tree = await service.getTree(); // Full hierarchy
const children = await service.getChildren("A.1"); // Direct children of A.1
const ancestors = await service.getAncestors("A.1.3"); // ["A", "A.1"]
const siblings = await service.getSiblings("A.1.3"); // Other A.1.x issues

// Query and filter
const inProgress = await service.findByState(CArtifactEvent.IN_PROGRESS);
const milestones = await service.findByType(CArtifact.MILESTONE);
const aliceWork = await service.findByAssignee("Alice ([email protected])");
const critical = await service.findByPriority(CPriority.CRITICAL);

// Complex queries
const results = await service.findArtifacts({
  state: "ready",
  type: CArtifact.ISSUE,
  assignee: "Alice ([email protected])",
  priority: CPriority.HIGH
});

Tree Methods:

  • getTree() - Returns full artifact hierarchy with lazy loading
  • getChildren(parentId) - Gets direct children of an artifact
  • getAncestors(id) - Returns array from root to parent (e.g., [A, A.1] for A.1.3)
  • getSiblings(id) - Returns artifacts with same parent

Query Methods:

  • findByState(state) - Filter by current state (draft, ready, in_progress, etc.)
  • findByType(type) - Filter by type (initiative, milestone, issue)
  • findByAssignee(assignee) - Filter by assignee
  • findByPriority(priority) - Filter by priority (low, medium, high, critical)
  • findArtifacts(criteria) - Multi-criteria queries with combinations

Performance:

  • Filters 1000+ artifacts in <100ms (with warm cache)
  • Two-level caching (path cache + artifact cache) for fast repeated queries
  • Lazy loading for tree traversal

DependencyGraphService

Operations for dependency graph analysis, blocking relationships, and circular dependency detection.

import { DependencyGraphService } from "@kodebase/artifacts";

const service = new DependencyGraphService();

// Dependency analysis
const deps = await service.getDependencies("A.1.3"); // Get blocked_by artifacts
const blocked = await service.getBlockedArtifacts("A.1.2"); // What does this block?
const isBlocked = await service.isBlocked("A.1.3"); // Check if ready to work on
const chain = await service.resolveDependencyChain("A.1.5"); // Full transitive closure

// Validation
const hasCircular = await service.hasCircularDependencies("A.1.2");
const crossLevel = await service.hasCrossLevelDependencies("A.1");
const consistent = await service.isRelationshipConsistent("A.1.2", "A.1.3");

Core Methods:

  • getDependencies(id) - Returns all artifacts in blocked_by array
  • getBlockedArtifacts(id) - Returns artifacts where this ID appears in their blocked_by
  • isBlocked(id) - Returns true if any blocked_by dependency is not completed
  • resolveDependencyChain(id) - Returns full transitive closure of dependencies

Validation Methods:

  • hasCircularDependencies(id) - Detects circular blocking relationships
  • hasCrossLevelDependencies(id) - Checks for invalid cross-level dependencies
  • isRelationshipConsistent(id1, id2) - Validates bidirectional relationship integrity

Features:

  • BFS with path tracking for circular dependency detection
  • Sibling-only constraint enforcement
  • Graceful handling of missing dependencies (warns, doesn't crash)
  • Performance: resolves 150+ artifact chains in <100ms

ReadinessService

Comprehensive readiness validation for artifact workflow and state transitions.

import { ReadinessService } from "@kodebase/artifacts";

const service = new ReadinessService();

// Readiness checks
const ready = await service.isReady("A.1.3"); // Can work start?
const allReady = await service.getReadyArtifacts(); // All ready artifacts
const reasons = await service.getBlockingReasons("A.1.3"); // Why not ready?
const canStart = await service.canTransitionToInProgress("A.1.3"); // Valid transition?

Methods:

  • isReady(id) - Returns true if artifact is ready to work on (no incomplete blocking siblings + ancestors completed if in ready state)
  • getReadyArtifacts() - Returns all artifacts ready to work on
  • getBlockingReasons(id) - Returns array of structured blocking reasons with ancestor diagnostics
  • canTransitionToInProgress(id) - Validates ready→in_progress state transition

Validation Rules:

  1. Sibling dependencies: No incomplete blocking siblings
  2. Ancestor validation: Full ancestor chain (Initiative→Milestone→Issue) must be complete if artifact has READY event
  3. State transitions: Only READY/IN_PROGRESS ancestors allow children to start; IN_REVIEW/COMPLETED block new work

Integration:

  • Uses DependencyGraphService for sibling dependency checks
  • Uses QueryService for parent traversal
  • Uses state machine from @kodebase/core for state validation
  • Performance: checks 100+ artifacts in <100ms

ValidationService

Orchestrates schema, dependency, and state machine validation with aggregated error reporting.

import { ValidationService } from "@kodebase/artifacts";

const service = new ValidationService();

// Validate a single artifact
const result = service.validateArtifact(artifact, {
  artifactId: "A.1.1",
  allArtifacts: artifactsMap,
  currentState: "ready",
  nextState: CArtifactEvent.IN_PROGRESS
});

if (!result.valid) {
  result.errors.forEach(err => {
    console.error(`${err.code}: ${err.message}`);
    if (err.suggestedFix) {
      console.log(`  Fix: ${err.suggestedFix}`);
    }
  });
}

// Batch validate all artifacts
const results = service.validateAll({
  artifacts: new Map([
    ["A.1", artifactA1],
    ["A.2", artifactA2]
  ])
});

const failed = results.filter(r => !r.valid);
console.log(`${failed.length} artifacts failed validation`);

Methods:

  • validateArtifact(artifact, options) - Validates single artifact through all validators
  • validateAll(options) - Batch validates multiple artifacts with optimization

Validation Checks:

  1. Schema validation - Zod schemas for initiative/milestone/issue
  2. Dependency validation - Circular, cross-level, and consistency checks
  3. State machine validation - Valid state transitions

Returns: ValidationResult with:

  • artifactId - Artifact being validated
  • valid - Boolean indicating pass/fail
  • errors - Array of validation errors with context
  • warnings - Array of non-blocking warnings

ScaffoldingService

High-level service for creating artifacts with auto-allocated IDs, generated slugs, and git-based actor detection.

import { ScaffoldingService, IdAllocationService } from "@kodebase/artifacts";

const idService = new IdAllocationService("/path/.kodebase/artifacts");
const service = new ScaffoldingService(idService);

// Scaffold a new initiative
const { id, artifact, slug } = await service.scaffoldInitiative(
  "Core Package Development",
  {
    vision: "Build production-ready core package",
    scopeIn: ["Types", "Schemas", "Validators"],
    scopeOut: ["CLI", "Web UI"],
    successCriteria: ["Package published", "95%+ test coverage"],
    assignee: "[email protected]",
    priority: CPriority.HIGH,
    estimation: CEstimationSize.L
  }
);

console.log(id);   // "C" (next available ID)
console.log(slug); // "core-package-development"

// Scaffold a milestone under initiative B
const milestone = await service.scaffoldMilestone("B", "API Implementation", {
  summary: "Implement REST API endpoints",
  deliverables: ["OpenAPI spec", "Rate limiting", "Auth middleware"],
  priority: CPriority.HIGH,
  estimation: CEstimationSize.M
});

// Scaffold an issue under milestone A.1
const issue = await service.scaffoldIssue("A.1", "Fix memory leak", {
  summary: "Memory leak in WebSocket connections",
  acceptanceCriteria: [
    "No memory growth after 1000 connections",
    "All tests pass",
    "Added regression test"
  ],
  priority: CPriority.CRITICAL,
  estimation: CEstimationSize.S
});

Methods:

  • scaffoldInitiative(title, metadata?) - Create initiative with auto-allocated ID
  • scaffoldMilestone(parentId, title, metadata?) - Create milestone under initiative
  • scaffoldIssue(parentId, title, metadata?) - Create issue under milestone

Features:

  • Automatically allocates next sequential ID (A, B, ..., Z, AA, AB, ...)
  • Generates URL-friendly slugs from titles
  • Detects git user info for createdBy field
  • Provides sensible defaults for all required fields
  • Returns ready-to-use artifact objects with draft event

See Also: @kodebase/core scaffolding functions for low-level artifact creation


IdAllocationService

Service for allocating unique sequential IDs for Kodebase artifacts.

import { IdAllocationService } from "@kodebase/artifacts";

const service = new IdAllocationService("/path/.kodebase/artifacts");

// Allocate next initiative ID
const initiativeId = await service.allocateNextInitiativeId();
// Returns: "A" (or next in sequence: B, C, ..., Z, AA, AB, ...)

// Allocate next milestone ID for initiative B
const milestoneId = await service.allocateNextMilestoneId("B");
// Returns: "B.1" (or B.2, B.3, etc.)

// Allocate next issue ID for milestone A.1
const issueId = await service.allocateNextIssueId("A.1");
// Returns: "A.1.1" (or A.1.2, A.1.3, etc.)

Methods:

  • allocateNextInitiativeId() - Returns next initiative ID in sequence
  • allocateNextMilestoneId(parentId) - Returns next milestone ID for initiative
  • allocateNextIssueId(parentId) - Returns next issue ID for milestone

ID Format:

  • Initiatives: Single or multiple uppercase letters (A, B, ..., Z, AA, AB, ...)
  • Milestones: Initiative ID + numeric suffix (A.1, A.2, B.1, ...)
  • Issues: Milestone ID + numeric suffix (A.1.1, A.1.2, B.2.1, ...)

Features:

  • Scans filesystem to determine next available ID
  • Prevents ID conflicts
  • Supports multi-letter initiatives (Z → AA → AB → ... → ZZ → AAA)
  • Base-26 conversion algorithm (similar to Excel columns)

ContextService

Service for detecting Kodebase project context and navigating to artifact root.

import { ContextService, NotInKodebaseProjectError } from "@kodebase/artifacts";

const service = new ContextService();

try {
  // Find .kodebase/artifacts from current directory
  const artifactsPath = await service.findArtifactsRoot();
  console.log(artifactsPath); // "/path/to/project/.kodebase/artifacts"

  // Find from specific starting directory
  const path = await service.findArtifactsRoot("/path/to/nested/dir");
} catch (error) {
  if (error instanceof NotInKodebaseProjectError) {
    console.error("Not in a Kodebase project");
    console.error(`Searched from: ${error.directory}`);
  }
}

Methods:

  • findArtifactsRoot(startDir?) - Searches upward for .kodebase/artifacts directory

Features:

  • Walks up directory tree to find project root
  • Returns absolute path to artifacts directory
  • Throws NotInKodebaseProjectError if not in a Kodebase project
  • Defaults to process.cwd() if no directory specified

Use Cases:

  • CLI commands that need to work from any subdirectory
  • IDEs/editors detecting project context
  • Scripts that validate artifact hierarchy

Error Formatting Utilities

User-friendly error messages for CLI output with artifact context and suggested fixes.

import {
  ArtifactError,
  formatValidationErrors,
  formatValidationWarnings,
  formatSchemaError,
  createUserFriendlyError
} from "@kodebase/artifacts";

// Create custom error with context
const error = new ArtifactError({
  code: "ARTIFACT_NOT_FOUND",
  message: "Artifact file not found",
  artifactId: "A.1.1",
  field: "metadata.relationships.blocks",
  suggestion: "Ensure the artifact exists before referencing it"
});

// Format validation errors for CLI
const errors = [
  {
    code: "RELATIONSHIP_INVALID_ID",
    message: "'invalid' is not a valid artifact ID",
    field: "metadata.relationships.blocks[0]",
    suggestedFix: "Use valid artifact ID format (e.g., A, A.1, A.1.1)"
  }
];

const output = formatValidationErrors(errors, "A.1.1");
console.error(output);
// ❌ Validation failed for artifact A.1.1
//
//   RELATIONSHIP_INVALID_ID (metadata.relationships.blocks[0]):
//     'invalid' is not a valid artifact ID
//     💡 Fix: Use valid artifact ID format (e.g., A, A.1, A.1.1)

// Convert Zod errors to ValidationError format
const zodIssues = zodError.issues;
const validationErrors = formatSchemaError(zodIssues, "A.1.1");

// Wrap unknown errors gracefully
try {
  await dangerousOperation();
} catch (error) {
  throw createUserFriendlyError(error, {
    code: "OPERATION_FAILED",
    artifactId: "A.1.1",
    suggestion: "Check file permissions and try again"
  });
}

Exports:

  • ArtifactError - Custom error class with artifact context
  • formatValidationErrors(errors, artifactId?, options?) - CLI-friendly error output
  • formatValidationWarnings(warnings, artifactId?, options?) - CLI-friendly warning output
  • formatSchemaError(issues, artifactId?) - Convert Zod errors to ValidationError
  • createUserFriendlyError(error, options?) - Wrap any error with context

Real-World Usage Examples

Building a CLI Command to Create Artifacts

import {
  ScaffoldingService,
  IdAllocationService,
  ContextService,
  ArtifactService,
  ValidationService,
  formatValidationErrors
} from "@kodebase/artifacts";

async function createIssue(title: string, summary: string) {
  // 1. Find project root
  const contextService = new ContextService();
  const artifactsPath = await contextService.findArtifactsRoot();

  // 2. Scaffold the issue with auto-allocated ID
  const idService = new IdAllocationService(artifactsPath);
  const scaffoldService = new ScaffoldingService(idService);

  const { id, artifact, slug } = await scaffoldService.scaffoldIssue("A.1", title, {
    summary,
    acceptanceCriteria: ["Implementation complete", "Tests pass"],
    priority: CPriority.MEDIUM,
    estimation: CEstimationSize.M
  });

  // 3. Validate before creating
  const validationService = new ValidationService();
  const result = validationService.validateArtifact(artifact, {
    artifactId: id
  });

  if (!result.valid) {
    console.error(formatValidationErrors(result.errors, id));
    process.exit(1);
  }

  // 4. Create the artifact file
  const artifactService = new ArtifactService(artifactsPath);
  const filePath = await artifactService.createArtifact({ id, artifact, slug });

  console.log(`✅ Created issue ${id} at ${filePath}`);
}

Building a Dashboard to Show Ready Work

import { QueryService, ReadinessService } from "@kodebase/artifacts";

async function getReadyWork() {
  const queryService = new QueryService();
  const readinessService = new ReadinessService();

  // Get all ready artifacts
  const ready = await readinessService.getReadyArtifacts();

  // Group by assignee
  const byAssignee = new Map<string, typeof ready>();

  for (const { id } of ready) {
    const artifact = await queryService.loadArtifact(id);
    const assignee = artifact.metadata.assignee || "Unassigned";

    if (!byAssignee.has(assignee)) {
      byAssignee.set(assignee, []);
    }
    byAssignee.get(assignee)!.push({ id, artifact });
  }

  // Display
  for (const [assignee, items] of byAssignee) {
    console.log(`\n${assignee} (${items.length} ready)`);
    for (const { id, artifact } of items) {
      console.log(`  • ${id}: ${artifact.metadata.title}`);
    }
  }
}

Validating Artifact Tree Before CI Merge

import {
  ValidationService,
  DependencyGraphService,
  QueryService,
  formatValidationErrors
} from "@kodebase/artifacts";

async function validateTree() {
  const queryService = new QueryService();
  const depService = new DependencyGraphService();
  const validationService = new ValidationService();

  // Load all artifacts
  const tree = await queryService.getTree();
  const allArtifacts = new Map<string, TAnyArtifact>();

  async function collectArtifacts(node: ArtifactTreeNode) {
    allArtifacts.set(node.id, node.artifact);
    for (const child of node.children) {
      await collectArtifacts(child);
    }
  }

  for (const root of tree) {
    await collectArtifacts(root);
  }

  // Batch validate
  const results = validationService.validateAll({ artifacts: allArtifacts });
  const failed = results.filter(r => !r.valid);

  if (failed.length > 0) {
    console.error(`❌ ${failed.length} artifacts failed validation\n`);

    for (const result of failed) {
      console.error(formatValidationErrors(result.errors, result.artifactId));
    }

    process.exit(1);
  }

  // Check for circular dependencies
  for (const [id] of allArtifacts) {
    const hasCircular = await depService.hasCircularDependencies(id);
    if (hasCircular) {
      console.error(`❌ Circular dependency detected in ${id}`);
      process.exit(1);
    }
  }

  console.log("✅ All artifacts valid");
}

Automated State Transitions Based on Dependencies

import {
  QueryService,
  DependencyGraphService,
  ArtifactService,
  ReadinessService
} from "@kodebase/artifacts";

async function autoTransitionToReady(artifactId: string) {
  const queryService = new QueryService();
  const depService = new DependencyGraphService();
  const artifactService = new ArtifactService();
  const readinessService = new ReadinessService();

  // Check if all dependencies are complete
  const isBlocked = await depService.isBlocked(artifactId);

  if (!isBlocked) {
    // Check if can transition to ready
    const canTransition = await readinessService.canTransitionToInProgress(artifactId);

    if (canTransition) {
      // Add ready event
      await artifactService.appendEvent({
        id: artifactId,
        event: {
          event: "ready",
          timestamp: new Date().toISOString(),
          actor: "automation ([email protected])",
          trigger: CEventTrigger.DEPENDENCIES_MET
        }
      });

      console.log(`✅ Auto-transitioned ${artifactId} to ready`);
    } else {
      const reasons = await readinessService.getBlockingReasons(artifactId);
      console.log(`⏸️  ${artifactId} still blocked:`, reasons);
    }
  }
}

Error Handling Patterns

Graceful Error Handling with Context

import {
  ArtifactService,
  ArtifactNotFoundError,
  NotInKodebaseProjectError,
  ContextService,
  createUserFriendlyError
} from "@kodebase/artifacts";

async function safeLoadArtifact(id: string) {
  try {
    const contextService = new ContextService();
    const artifactsPath = await contextService.findArtifactsRoot();
    const service = new ArtifactService(artifactsPath);

    return await service.getArtifact({ id });
  } catch (error) {
    if (error instanceof ArtifactNotFoundError) {
      console.error(`❌ Artifact ${error.artifactId} not found`);
      console.error(`   Expected at: ${error.filePath}`);
      console.error(`   💡 Tip: Use 'ls' to list available artifacts`);
      process.exit(1);
    }

    if (error instanceof NotInKodebaseProjectError) {
      console.error("❌ Not in a Kodebase project");
      console.error(`   Searched from: ${error.directory}`);
      console.error(`   💡 Tip: Run 'kodebase init' or navigate to project root`);
      process.exit(1);
    }

    // Wrap unexpected errors with context
    throw createUserFriendlyError(error, {
      code: "LOAD_ARTIFACT_FAILED",
      artifactId: id,
      suggestion: "Check file permissions and artifact structure"
    });
  }
}

Validation Error Handling

import { ValidationService, formatValidationErrors } from "@kodebase/artifacts";

function handleValidation(artifact: TAnyArtifact, id: string) {
  const service = new ValidationService();
  const result = service.validateArtifact(artifact, { artifactId: id });

  if (!result.valid) {
    // Format errors for CLI output
    const errorOutput = formatValidationErrors(result.errors, id, {
      showField: true,
      showSuggestion: true
    });

    console.error(errorOutput);

    // Log structured data for debugging
    console.error("\nDetailed errors:", JSON.stringify(result.errors, null, 2));

    return false;
  }

  // Handle warnings (non-blocking)
  if (result.warnings.length > 0) {
    const warningOutput = formatValidationWarnings(result.warnings, id);
    console.warn(warningOutput);
  }

  return true;
}

Dependency Resolution with Fallbacks

import { DependencyGraphService, QueryService } from "@kodebase/artifacts";

async function resolveDependenciesWithFallback(artifactId: string) {
  const depService = new DependencyGraphService();
  const queryService = new QueryService();

  try {
    // Try to resolve full dependency chain
    const chain = await depService.resolveDependencyChain(artifactId);

    console.log(`Dependency chain for ${artifactId}:`);
    for (const node of chain) {
      const artifact = await queryService.loadArtifact(node.artifactId);
      console.log(`  ${node.depth === 0 ? "→" : "  ".repeat(node.depth) + "↳"} ${node.artifactId}: ${artifact.metadata.title}`);
    }

    return chain;
  } catch (error) {
    // Fall back to direct dependencies only
    console.warn(`⚠️  Could not resolve full chain, showing direct dependencies only`);

    const directDeps = await depService.getDependencies(artifactId);
    console.log(`Direct dependencies: ${directDeps.map(a => a.id).join(", ") || "none"}`);

    return directDeps.map((artifact, idx) => ({
      artifactId: artifact.id,
      depth: 1,
      path: [artifactId, artifact.id]
    }));
  }
}

Performance Considerations

Caching Strategy

All services use multi-level caching to optimize repeated queries:

QueryService and DependencyGraphService:

  • Path cache: Maps artifact IDs to file paths (lazy-loaded once)
  • Artifact cache: Stores loaded artifact objects in memory
  • Performance: 1000+ artifacts filtered in <100ms with warm cache
const service = new QueryService();

// First call: loads from disk and builds path cache
const tree1 = await service.getTree(); // ~500ms for 150 artifacts

// Subsequent calls: uses in-memory cache
const tree2 = await service.getTree(); // ~5ms

// Clear cache when artifact files change
service.clearCache();

Batch Operations

Use batch operations to reduce I/O overhead:

import { ValidationService, QueryService } from "@kodebase/artifacts";

// ❌ Slow: validates one at a time
for (const [id, artifact] of artifacts) {
  await validationService.validateArtifact(artifact, { artifactId: id });
}

// ✅ Fast: batch validates with shared context
const results = validationService.validateAll({ artifacts });

Lazy Loading

Tree traversal operations use lazy loading to avoid loading entire tree upfront:

const service = new QueryService();

// Only loads ancestors, not entire tree
const ancestors = await service.getAncestors("A.1.5");

// Only loads children of specific parent
const children = await service.getChildren("A.1");

// Loads full tree (heavier operation)
const tree = await service.getTree();

Best Practices

  1. Reuse service instances: Service instances cache data, so reuse them within a workflow
  2. Batch validation: Use validateAll() instead of individual validateArtifact() calls
  3. Clear cache when modifying: Call clearCache() after creating/updating artifacts
  4. Use specific queries: Prefer getChildren() over getTree() when possible
  5. Handle errors early: Validate inputs before expensive operations

Migration Guide

Migrating from Legacy @kodebase/artifact-* Packages

If you were using the deprecated @kodebase/artifact-validation, @kodebase/artifact-query, or similar packages, here's how to migrate:

Before (Legacy)

import { validateArtifact } from "@kodebase/artifact-validation";
import { queryArtifacts } from "@kodebase/artifact-query";
import { createArtifact } from "@kodebase/artifact-manager";

// Legacy validation
const result = validateArtifact(artifact);

// Legacy query
const results = await queryArtifacts({ state: CArtifactEvent.READY });

// Legacy create
await createArtifact(id, artifact);

After (Current)

import {
  ValidationService,
  QueryService,
  ArtifactService
} from "@kodebase/artifacts";

// Current validation
const validationService = new ValidationService();
const result = validationService.validateArtifact(artifact, { artifactId: id });

// Current query
const queryService = new QueryService();
const results = await queryService.findByState(CArtifactEvent.READY);

// Current create
const artifactService = new ArtifactService();
await artifactService.createArtifact({ id, artifact, slug: "my-artifact" });

Key Changes

  1. Service-based API: All operations now go through service classes instead of standalone functions
  2. Explicit context: Pass artifactId explicitly to validation for better error messages
  3. Options objects: Methods use options objects instead of positional parameters
  4. Dependency injection: Services like ScaffoldingService take dependencies (e.g., IdAllocationService) as constructor parameters

Incremental Migration

You can migrate incrementally by running both packages side-by-side:

{
  "dependencies": {
    "@kodebase/core": "^0.1.0",
    "@kodebase/artifacts": "^0.3.0"
  }
}

Start by migrating one workflow at a time, using the new API for new features while keeping legacy code functional.


Type Exports

All types from services and utilities are exported for TypeScript users:

import type {
  // ArtifactService types
  TAnyArtifact,
  CreateArtifactOptions,
  GetArtifactOptions,
  UpdateMetadataOptions,
  AppendEventOptions,

  // QueryService types
  ArtifactTreeNode,
  ArtifactWithId,
  QueryCriteria,

  // DependencyGraphService types
  DependencyChainNode,

  // ReadinessService types
  BlockingReason,

  // ValidationService types
  ValidationResult,
  ValidationError,
  ValidationWarning,
  ValidateArtifactOptions,
  ValidateAllOptions,

  // Error formatting types
  FormatValidationErrorsOptions,
  SchemaErrorIssue,
  CreateUserFriendlyErrorOptions
} from "@kodebase/artifacts";

Package Features

  • ESM-only - Modern ES module distribution for tree-shaking
  • Tree-shakable - Import only what you use for optimal bundle size
  • Strict TypeScript - Full type safety with strict mode enabled
  • Zero circular dependencies - Clean module structure verified with madge
  • Comprehensive tests - 96%+ coverage with memfs-based fast tests
  • Type declarations - Full .d.ts with source maps for IDE navigation

Dependencies

This package requires @kodebase/core for underlying types, schemas, and file operations:

// Core types and schemas available via @kodebase/core
import {
  TInitiative,
  TMilestone,
  TIssue,
  scaffoldInitiative,
  scaffoldMilestone,
  scaffoldIssue,
  readArtifact,
  writeArtifact
} from "@kodebase/core";

See @kodebase/core documentation for available schemas, validators, and file operations.


API Reference

For complete API documentation with detailed parameter descriptions, return types, and additional examples, see the generated TypeDoc documentation (coming soon) or refer to the inline JSDoc comments in the source code.

All public APIs are fully documented with:

  • Parameter descriptions and types
  • Return type documentation
  • Thrown error documentation
  • Usage examples with multiple scenarios
  • Cross-references to related methods

Example of viewing JSDoc in your IDE:

import { ScaffoldingService } from "@kodebase/artifacts";

// Hover over the method to see full documentation
const service = new ScaffoldingService(idService);
const result = await service.scaffoldInitiative(/*...*/);

License

MIT