atomism 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +210 -0
- package/dist/chunk-34O5KJWR.js +81 -0
- package/dist/chunk-34O5KJWR.js.map +1 -0
- package/dist/chunk-55AP34JO.js +116 -0
- package/dist/chunk-55AP34JO.js.map +1 -0
- package/dist/chunk-6MDHM2B4.js +17 -0
- package/dist/chunk-6MDHM2B4.js.map +1 -0
- package/dist/chunk-GU2R4KLP.js +43 -0
- package/dist/chunk-GU2R4KLP.js.map +1 -0
- package/dist/chunk-H7WC3NXZ.js +39 -0
- package/dist/chunk-H7WC3NXZ.js.map +1 -0
- package/dist/chunk-P33CQFMY.js +329 -0
- package/dist/chunk-P33CQFMY.js.map +1 -0
- package/dist/chunk-P6X7T4KA.js +200 -0
- package/dist/chunk-P6X7T4KA.js.map +1 -0
- package/dist/chunk-PLQJM2KT.js +9 -0
- package/dist/chunk-PLQJM2KT.js.map +1 -0
- package/dist/chunk-RS2IEGW3.js +10 -0
- package/dist/chunk-RS2IEGW3.js.map +1 -0
- package/dist/chunk-S6Z5G5DB.js +84 -0
- package/dist/chunk-S6Z5G5DB.js.map +1 -0
- package/dist/chunk-UVUDQ4XP.js +259 -0
- package/dist/chunk-UVUDQ4XP.js.map +1 -0
- package/dist/chunk-UWVZQSP4.js +597 -0
- package/dist/chunk-UWVZQSP4.js.map +1 -0
- package/dist/chunk-YKJO3ZFY.js +308 -0
- package/dist/chunk-YKJO3ZFY.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +152 -0
- package/dist/cli.js.map +1 -0
- package/dist/create-atom-AXPDBYQL.js +153 -0
- package/dist/create-atom-AXPDBYQL.js.map +1 -0
- package/dist/escalate-BTEJT5NL.js +211 -0
- package/dist/escalate-BTEJT5NL.js.map +1 -0
- package/dist/extract-RPKCTINT.js +514 -0
- package/dist/extract-RPKCTINT.js.map +1 -0
- package/dist/graduate-453M7ZRQ.js +222 -0
- package/dist/graduate-453M7ZRQ.js.map +1 -0
- package/dist/helpers-PJPFPYBQ.js +11 -0
- package/dist/helpers-PJPFPYBQ.js.map +1 -0
- package/dist/history-OPD7NLZW.js +258 -0
- package/dist/history-OPD7NLZW.js.map +1 -0
- package/dist/import-generator-4CKRBMTE.js +1864 -0
- package/dist/import-generator-4CKRBMTE.js.map +1 -0
- package/dist/index.d.ts +230 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/init-2FINDMYK.js +741 -0
- package/dist/init-2FINDMYK.js.map +1 -0
- package/dist/list-NEBVBGG3.js +71 -0
- package/dist/list-NEBVBGG3.js.map +1 -0
- package/dist/parser-3BILOSOO.js +157 -0
- package/dist/parser-3BILOSOO.js.map +1 -0
- package/dist/plan-DNVARHWH.js +249 -0
- package/dist/plan-DNVARHWH.js.map +1 -0
- package/dist/register-XTRMSH7Y.js +91 -0
- package/dist/register-XTRMSH7Y.js.map +1 -0
- package/dist/revert-J4CRDE2K.js +87 -0
- package/dist/revert-J4CRDE2K.js.map +1 -0
- package/dist/run-3GI3SBYL.js +188 -0
- package/dist/run-3GI3SBYL.js.map +1 -0
- package/dist/scan-generators-ST4TBEY7.js +375 -0
- package/dist/scan-generators-ST4TBEY7.js.map +1 -0
- package/dist/signatures-K5QIL4WG.js +258 -0
- package/dist/signatures-K5QIL4WG.js.map +1 -0
- package/dist/skills-assign-IHOXX4AI.js +182 -0
- package/dist/skills-assign-IHOXX4AI.js.map +1 -0
- package/dist/skills-load-JSD5UG2K.js +20 -0
- package/dist/skills-load-JSD5UG2K.js.map +1 -0
- package/dist/skills-scan-WACJFRJN.js +25 -0
- package/dist/skills-scan-WACJFRJN.js.map +1 -0
- package/dist/skills-suggest-JFI2NUJI.js +269 -0
- package/dist/skills-suggest-JFI2NUJI.js.map +1 -0
- package/dist/status-KQVSAZFR.js +111 -0
- package/dist/status-KQVSAZFR.js.map +1 -0
- package/dist/suggest-IFFJQFIW.js +183 -0
- package/dist/suggest-IFFJQFIW.js.map +1 -0
- package/dist/test-HP3FG3MO.js +152 -0
- package/dist/test-HP3FG3MO.js.map +1 -0
- package/dist/test-gen-2ZGPOP35.js +347 -0
- package/dist/test-gen-2ZGPOP35.js.map +1 -0
- package/dist/trust-4R26DULG.js +248 -0
- package/dist/trust-4R26DULG.js.map +1 -0
- package/dist/validate-generator-46H2LYYQ.js +410 -0
- package/dist/validate-generator-46H2LYYQ.js.map +1 -0
- package/dist/workflow-5UVLBS7J.js +655 -0
- package/dist/workflow-5UVLBS7J.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/workflow/resolver.ts","../src/workflow/dag.ts","../src/workflow/beads.ts","../src/workflow/run-state.ts"],"sourcesContent":["/**\n * Artifact dependency resolution for workflows.\n *\n * This module provides Make/Terraform-like dependency resolution:\n * - Atoms declare what artifacts they produce and require\n * - Artifacts flow from producers to consumers automatically\n * - Unchanged artifacts are cached (skip rebuild)\n *\n * @module workflow/resolver\n */\n\nimport { z } from 'zod';\nimport { createHash } from 'node:crypto';\nimport { topologicalSort, dependencyChain } from './dag.js';\nimport type { WorkflowDefinition } from '../schemas/workflow.js';\n\n/**\n * An artifact requirement - what an atom needs from dependencies.\n */\nexport const ArtifactRequirement = z.object({\n /** The artifact name to require */\n artifact: z.string().min(1),\n /** Which atom produces this artifact (must be in dependsOn) */\n from: z.string().min(1),\n /** Optional: map to a different input name (must be non-empty if provided) */\n as: z.string().min(1).optional(),\n});\nexport type ArtifactRequirement = z.infer<typeof ArtifactRequirement>;\n\n/**\n * An artifact production declaration - what an atom produces.\n */\nexport const ArtifactProduction = z.object({\n /** The artifact name to produce */\n artifact: z.string().min(1),\n /** Optional description of the artifact */\n description: z.string().optional(),\n});\nexport type ArtifactProduction = z.infer<typeof ArtifactProduction>;\n\n/**\n * Extended workflow atom with artifact declarations.\n */\nexport const AtomWithArtifacts = z.object({\n /** Atom name (must match a registered atom) */\n atom: z.string().min(1),\n /** Atoms this depends on (must complete before this runs) */\n dependsOn: z.array(z.string().min(1)).default([]),\n /** Optional alias for this atom instance in the workflow (must be non-empty if provided) */\n alias: z.string().min(1).optional(),\n /** Optional description of this atom's role in the workflow */\n description: z.string().optional(),\n /** Artifacts this atom requires (from dependencies) */\n requires: z.array(ArtifactRequirement).default([]),\n /** Artifacts this atom produces */\n produces: z.array(ArtifactProduction).default([]),\n});\nexport type AtomWithArtifacts = z.infer<typeof AtomWithArtifacts>;\n\n/**\n * A cached artifact reference.\n */\nexport interface CachedArtifact {\n /** Content hash (SHA-256) */\n hash: string;\n /** When the artifact was cached */\n cachedAt: string;\n /** The actual content (or path to content) */\n content: string | Buffer;\n}\n\n/**\n * Artifact cache for Make-like dependency resolution.\n */\nexport interface ArtifactCache {\n /** Get a cached artifact by atom ID and artifact name */\n get(atomId: string, artifactName: string): CachedArtifact | undefined;\n /** Store an artifact in the cache */\n set(atomId: string, artifactName: string, artifact: CachedArtifact): void;\n /** Check if an artifact is cached */\n has(atomId: string, artifactName: string): boolean;\n /** Clear a specific artifact from cache */\n clear(atomId: string, artifactName: string): void;\n /** Clear all cached artifacts */\n clearAll(): void;\n}\n\n/**\n * Create an in-memory artifact cache.\n */\nexport function createArtifactCache(): ArtifactCache {\n // Use nested maps to avoid key collision issues\n const cache = new Map<string, Map<string, CachedArtifact>>();\n\n return {\n get(atomId: string, artifactName: string): CachedArtifact | undefined {\n return cache.get(atomId)?.get(artifactName);\n },\n set(atomId: string, artifactName: string, artifact: CachedArtifact): void {\n let atomCache = cache.get(atomId);\n if (!atomCache) {\n atomCache = new Map<string, CachedArtifact>();\n cache.set(atomId, atomCache);\n }\n atomCache.set(artifactName, artifact);\n },\n has(atomId: string, artifactName: string): boolean {\n return cache.get(atomId)?.has(artifactName) ?? false;\n },\n clear(atomId: string, artifactName: string): void {\n const atomCache = cache.get(atomId);\n if (!atomCache) return;\n atomCache.delete(artifactName);\n if (atomCache.size === 0) {\n cache.delete(atomId);\n }\n },\n clearAll(): void {\n cache.clear();\n },\n };\n}\n\n/**\n * Result of dependency resolution for a single atom.\n */\nexport interface ResolvedAtom {\n /** The atom ID (alias or atom name) */\n id: string;\n /** The original atom definition */\n atom: AtomWithArtifacts;\n /** Resolved artifact inputs (from dependencies) */\n inputs: Map<string, CachedArtifact>;\n /** Whether this atom can be skipped (all outputs cached and unchanged) */\n canSkip: boolean;\n /** Reason for skip/rebuild decision */\n reason: string;\n}\n\n/**\n * Result of full workflow dependency resolution.\n */\nexport interface ResolutionResult {\n /** Atoms in execution order with resolved inputs */\n resolved: ResolvedAtom[];\n /** Atoms that will be skipped (cached) */\n skipped: string[];\n /** Atoms that will be executed */\n toExecute: string[];\n}\n\n/**\n * Options for dependency resolution.\n */\nexport interface ResolveOptions {\n /** Artifact cache to check for cached outputs */\n cache?: ArtifactCache;\n /** Force rebuild of specific atoms */\n forceRebuild?: string[];\n /** Force rebuild all atoms */\n forceRebuildAll?: boolean;\n}\n\n/**\n * Resolve artifact dependencies for a workflow.\n *\n * This function:\n * 1. Computes execution order (topological sort)\n * 2. Resolves artifact inputs from dependencies\n * 3. Determines which atoms can be skipped (cached)\n *\n * @param atoms - The workflow atoms with artifact declarations\n * @param options - Resolution options (cache, force rebuild, etc.)\n * @returns ResolutionResult with resolved atoms\n */\nexport function resolveDependencies(\n atoms: AtomWithArtifacts[],\n options: ResolveOptions = {}\n): ResolutionResult {\n // Validate artifact dependencies before resolution\n validateArtifactDependencies(atoms);\n\n const { cache, forceRebuild = [], forceRebuildAll = false } = options;\n const forceRebuildSet = new Set(forceRebuild);\n\n // Build atom lookup (reject duplicates)\n const atomMap = new Map<string, AtomWithArtifacts>();\n for (const a of atoms) {\n const id = a.alias ?? a.atom;\n if (atomMap.has(id)) {\n throw new Error(`Duplicate atom id \"${id}\"`);\n }\n atomMap.set(id, a);\n }\n\n // Validate forceRebuild targets\n if (!forceRebuildAll) {\n for (const id of forceRebuildSet) {\n if (!atomMap.has(id)) {\n throw new Error(`forceRebuild references unknown atom \"${id}\"`);\n }\n }\n }\n\n // Topological sort\n const dagNodes = atoms.map(a => ({\n id: a.alias ?? a.atom,\n dependsOn: [...a.dependsOn],\n }));\n const executionOrder = topologicalSort(dagNodes);\n\n // Track what each atom produces (for downstream resolution)\n const productions = new Map<string, Map<string, CachedArtifact>>();\n\n const resolved: ResolvedAtom[] = [];\n const skipped: string[] = [];\n const toExecute: string[] = [];\n\n // First pass: determine which atoms can be skipped vs need to execute\n // and set up their production declarations\n const atomStatus = new Map<string, { canSkip: boolean; reason: string }>();\n\n for (const id of executionOrder) {\n const a = atomMap.get(id)!;\n\n let canSkip = false;\n let reason = 'No cache available';\n\n if (cache && !forceRebuildAll && !forceRebuildSet.has(id)) {\n // Check if all outputs are cached (only if there are outputs to cache)\n const hasOutputs = a.produces.length > 0;\n const allOutputsCached =\n hasOutputs &&\n a.produces.every((prod) => cache.has(id, prod.artifact));\n // Check if all dependencies can be skipped (if any will run, we must run too)\n const depsSkippable = a.dependsOn.every(\n (dep) => atomStatus.get(dep)?.canSkip\n );\n\n if (hasOutputs && allOutputsCached && depsSkippable) {\n canSkip = true;\n reason = 'All outputs cached';\n // Use cached outputs for downstream atoms\n const cachedProductions = new Map<string, CachedArtifact>();\n for (const prod of a.produces) {\n const cached = cache.get(id, prod.artifact);\n if (cached) {\n cachedProductions.set(prod.artifact, cached);\n }\n }\n productions.set(id, cachedProductions);\n skipped.push(id);\n } else {\n if (!depsSkippable) {\n reason = 'Dependency rebuild required';\n } else if (!hasOutputs) {\n reason = 'No outputs to cache';\n } else {\n reason = 'Some outputs not cached';\n }\n toExecute.push(id);\n // Create placeholder productions for dependency tracking\n // These are empty but declared so downstream knows what artifacts will exist\n const placeholderProductions = new Map<string, CachedArtifact>();\n productions.set(id, placeholderProductions);\n }\n } else if (forceRebuildAll) {\n reason = 'Force rebuild all';\n toExecute.push(id);\n productions.set(id, new Map<string, CachedArtifact>());\n } else if (forceRebuildSet.has(id)) {\n reason = `Force rebuild: ${id}`;\n toExecute.push(id);\n productions.set(id, new Map<string, CachedArtifact>());\n } else {\n toExecute.push(id);\n productions.set(id, new Map<string, CachedArtifact>());\n }\n\n atomStatus.set(id, { canSkip, reason });\n }\n\n // Second pass: resolve inputs for each atom\n for (const id of executionOrder) {\n const a = atomMap.get(id)!;\n const status = atomStatus.get(id)!;\n const inputs = new Map<string, CachedArtifact>();\n\n // Resolve inputs from dependencies\n for (const req of a.requires) {\n const depProductions = productions.get(req.from);\n if (!depProductions) {\n throw new Error(\n `Atom \"${id}\" requires artifact \"${req.artifact}\" from \"${req.from}\", but \"${req.from}\" has not been resolved yet`\n );\n }\n\n // For skipped dependencies, we have cached artifacts\n // For to-execute dependencies, we note the requirement but artifacts will be provided at runtime\n const artifact = depProductions.get(req.artifact);\n if (artifact) {\n // Use cached artifact if available\n const inputName = req.as ?? req.artifact;\n inputs.set(inputName, artifact);\n }\n // If artifact is not available yet (dependency will execute), that's OK\n // The runtime will provide it after execution\n }\n\n resolved.push({\n id,\n atom: a,\n inputs,\n canSkip: status.canSkip,\n reason: status.reason,\n });\n }\n\n return {\n resolved,\n skipped,\n toExecute,\n };\n}\n\n/**\n * Validate artifact dependencies.\n *\n * Checks that:\n * - All required artifacts come from declared dependencies\n * - All referenced atoms exist\n * - No circular artifact dependencies (beyond atom dependencies)\n *\n * @param atoms - The atoms to validate\n * @throws Error if validation fails\n */\nexport function validateArtifactDependencies(\n atoms: AtomWithArtifacts[]\n): void {\n const atomMap = new Map<string, AtomWithArtifacts>();\n for (const a of atoms) {\n const id = a.alias ?? a.atom;\n atomMap.set(id, a);\n }\n\n for (const a of atoms) {\n const id = a.alias ?? a.atom;\n const deps = new Set(a.dependsOn);\n const inputNames = new Set<string>();\n\n for (const req of a.requires) {\n // Check for duplicate input names\n const inputName = req.as ?? req.artifact;\n if (inputNames.has(inputName)) {\n throw new Error(\n `Atom \"${id}\" has duplicate input mapping \"${inputName}\"`\n );\n }\n inputNames.add(inputName);\n\n // Check that the required atom is in dependsOn\n if (!deps.has(req.from)) {\n throw new Error(\n `Atom \"${id}\" requires artifact \"${req.artifact}\" from \"${req.from}\", but \"${req.from}\" is not in dependsOn`\n );\n }\n\n // Check that the required atom exists\n if (!atomMap.has(req.from)) {\n throw new Error(\n `Atom \"${id}\" requires artifact from unknown atom \"${req.from}\"`\n );\n }\n\n // Check that the required atom produces the artifact\n const producer = atomMap.get(req.from)!;\n const producesArtifact = producer.produces.some(\n (p) => p.artifact === req.artifact\n );\n if (!producesArtifact) {\n throw new Error(\n `Atom \"${id}\" requires artifact \"${req.artifact}\" from \"${req.from}\", but \"${req.from}\" does not produce it`\n );\n }\n }\n }\n}\n\n/**\n * Record a produced artifact.\n *\n * Call this after an atom executes to record its outputs.\n *\n * @param atomId - The atom ID\n * @param artifactName - The artifact name\n * @param content - The artifact content\n * @param cache - The artifact cache to update\n * @returns The cached artifact reference\n */\nexport function recordArtifact(\n atomId: string,\n artifactName: string,\n content: string | Buffer,\n cache: ArtifactCache\n): CachedArtifact {\n const buffer: Buffer = typeof content === 'string' ? Buffer.from(content, 'utf-8') : content;\n const hash = createHash('sha256').update(buffer).digest('hex');\n\n const artifact: CachedArtifact = {\n hash,\n cachedAt: new Date().toISOString(),\n content,\n };\n\n cache.set(atomId, artifactName, artifact);\n return artifact;\n}\n\n/**\n * Get the dependency chain for a specific atom.\n *\n * Returns an array of atom IDs in execution order (dependencies first).\n * This is useful for displaying what will run when an atom is requested.\n *\n * @param atoms - All available atoms\n * @param targetId - The atom to get the chain for\n * @returns Array of atom IDs in execution order (ending with targetId)\n */\nexport function getDependencyChain(\n atoms: AtomWithArtifacts[],\n targetId: string\n): string[] {\n return dependencyChain(\n atoms.map(a => ({\n id: a.alias ?? a.atom,\n dependsOn: [...a.dependsOn],\n })),\n targetId\n );\n}\n\n/**\n * Format a dependency chain for display.\n *\n * @param chain - Array of atom IDs in execution order\n * @returns Formatted string like \"A → B → C\"\n */\nexport function formatDependencyChain(chain: string[]): string {\n return chain.join(' → ');\n}\n\n/**\n * Get topological sort of atoms (execution order).\n * Returns atoms in an order where dependencies come before dependents.\n *\n * @param workflow - The workflow to sort\n * @returns Array of atom identifiers in execution order\n * @throws Error if cycle detected (should not happen if validateWorkflow passed)\n */\nexport function getExecutionOrder(workflow: WorkflowDefinition): string[] {\n return topologicalSort(\n workflow.atoms.map(a => ({\n id: a.alias ?? a.atom,\n dependsOn: [...a.dependsOn],\n }))\n );\n}\n\n","/**\n * Generic DAG (Directed Acyclic Graph) utilities for topological sorting.\n *\n * Provides a single canonical implementation of topological sort used by\n * workflow execution ordering, dependency chain resolution, and plan commands.\n *\n * @module workflow/dag\n */\n\nexport interface DagNode {\n /** Unique identifier for this node. */\n id: string;\n /** IDs of nodes this node depends on (must complete before this node). */\n dependsOn: string[];\n}\n\n/**\n * DFS post-order visit with cycle detection.\n *\n * Shared traversal logic used by both topologicalSort and dependencyChain.\n * Pushes visited node IDs onto `result` in dependency-first order.\n */\nfunction dfsVisit(\n id: string,\n nodeMap: Map<string, DagNode>,\n visited: Set<string>,\n visiting: Set<string>,\n result: string[],\n): void {\n if (visited.has(id)) return;\n if (visiting.has(id)) {\n throw new Error(`Cycle detected at \"${id}\"`);\n }\n visiting.add(id);\n const node = nodeMap.get(id);\n if (!node) {\n throw new Error(`Unknown node \"${id}\"`);\n }\n for (const dep of node.dependsOn) {\n if (!nodeMap.has(dep)) {\n throw new Error(`Node \"${id}\" depends on unknown node \"${dep}\"`);\n }\n dfsVisit(dep, nodeMap, visited, visiting, result);\n }\n visiting.delete(id);\n visited.add(id);\n result.push(id);\n}\n\n/** Build a lookup map from an array of DagNodes. Throws on duplicate IDs. */\nfunction buildNodeMap(nodes: DagNode[]): Map<string, DagNode> {\n const nodeMap = new Map<string, DagNode>();\n for (const node of nodes) {\n if (nodeMap.has(node.id)) {\n throw new Error(`Duplicate node ID \"${node.id}\"`);\n }\n nodeMap.set(node.id, node);\n }\n return nodeMap;\n}\n\n/**\n * Topological sort via DFS with cycle detection.\n *\n * Returns node IDs in execution order: dependencies before dependents.\n * Visits all nodes in the graph.\n *\n * @param nodes - All nodes in the graph\n * @returns Array of node IDs in topological order\n * @throws Error if a cycle is detected or a dependency references an unknown node\n */\nexport function topologicalSort(nodes: DagNode[]): string[] {\n const result: string[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const nodeMap = buildNodeMap(nodes);\n for (const node of nodes) {\n dfsVisit(node.id, nodeMap, visited, visiting, result);\n }\n return result;\n}\n\n/**\n * Get the dependency chain for a single target node.\n *\n * Returns node IDs in execution order, starting from the deepest\n * dependency and ending with the target. Only includes nodes\n * reachable from the target.\n *\n * @param nodes - All nodes in the graph\n * @param targetId - The node to get the dependency chain for\n * @returns Array of node IDs in execution order (ending with targetId)\n * @throws Error if targetId is unknown, a cycle is detected, or a dependency is unknown\n */\nexport function dependencyChain(nodes: DagNode[], targetId: string): string[] {\n const nodeMap = buildNodeMap(nodes);\n if (!nodeMap.has(targetId)) {\n throw new Error(`Unknown node \"${targetId}\"`);\n }\n const result: string[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>();\n dfsVisit(targetId, nodeMap, visited, visiting, result);\n return result;\n}\n","/**\n * Beads integration for workflow tracking.\n *\n * This module provides functions to create and update Beads issues\n * for tracking workflow execution progress.\n *\n * @module workflow/beads\n */\n\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { platform } from 'node:os';\nimport { z } from 'zod';\nimport { toErrorMessage } from '../utils/errors.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Schema for workflow bead options.\n */\nexport const WorkflowBeadOptionsSchema = z.object({\n workflow: z.string().min(1),\n description: z.string().optional(),\n atoms: z.array(z.string().min(1)),\n});\n\nexport type WorkflowBeadOptions = z.infer<typeof WorkflowBeadOptionsSchema>;\n\n/**\n * Result of creating a workflow bead (discriminated union on `success`).\n */\nexport type WorkflowBeadResult =\n | { success: true; parentId: string; childIds: Map<string, string> }\n | { success: false; error: string };\n\n/**\n * Status for atom beads.\n */\nexport type AtomBeadStatus = 'pending' | 'in_progress' | 'completed' | 'failed';\n\n/**\n * Check if Beads (bd) CLI is available.\n * Uses execFile with array args to avoid shell injection.\n */\nexport async function isBeadsAvailable(): Promise<boolean> {\n try {\n const cmd = platform() === 'win32' ? 'where' : 'which';\n await execFileAsync(cmd, ['bd'], {});\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if Beads is initialized in the current directory.\n */\nexport async function isBeadsInitialized(): Promise<boolean> {\n try {\n await execFileAsync('bd', ['info'], {});\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Create a Beads issue.\n * Uses execFile with array args to avoid shell injection.\n */\nasync function createBead(\n title: string,\n description: string,\n labels: string[],\n parentId?: string\n): Promise<{ id: string } | { error: string }> {\n try {\n const args = ['create', title, '-d', description];\n for (const label of labels) {\n args.push('-l', label);\n }\n args.push('-t', 'task', '--json');\n\n // Add parent reference if provided\n if (parentId) {\n args.push('--parent', parentId);\n }\n\n const { stdout } = await execFileAsync('bd', args, {\n encoding: 'utf-8',\n });\n\n const parsed = JSON.parse(stdout);\n if (parsed.id) {\n return { id: parsed.id };\n }\n return { error: 'Failed to parse bead ID from output' };\n } catch (err) {\n return {\n error: toErrorMessage(err),\n };\n }\n}\n\n/**\n * Update a Beads issue status.\n */\nasync function updateBeadStatus(\n beadId: string,\n status: string,\n comment?: string\n): Promise<{ success: boolean; error?: string }> {\n try {\n const args = ['update', beadId, '--status', status];\n if (comment) {\n args.push('-c', comment);\n }\n\n await execFileAsync('bd', args, {\n encoding: 'utf-8',\n });\n\n return { success: true };\n } catch (err) {\n return {\n success: false,\n error: toErrorMessage(err),\n };\n }\n}\n\n/**\n * Create workflow beads with parent and child structure.\n *\n * @param options - Workflow bead options\n * @returns Result with parent and child bead IDs\n */\nexport async function createWorkflowBeads(\n options: WorkflowBeadOptions\n): Promise<WorkflowBeadResult> {\n // Validate options\n const parseResult = WorkflowBeadOptionsSchema.safeParse(options);\n if (!parseResult.success) {\n return {\n success: false,\n error: `Invalid options: ${parseResult.error.message}`,\n };\n }\n const validated = parseResult.data;\n\n // Check Beads availability\n if (!(await isBeadsAvailable())) {\n return {\n success: false,\n error: 'Beads CLI (bd) not found',\n };\n }\n\n if (!(await isBeadsInitialized())) {\n return {\n success: false,\n error: 'Beads not initialized in this directory',\n };\n }\n\n // Create parent bead for workflow\n const parentDescription = buildParentDescription(validated);\n const parentResult = await createBead(\n `[atomic] Workflow: ${validated.workflow}`,\n parentDescription,\n ['atomic', 'workflow']\n );\n\n if ('error' in parentResult) {\n return {\n success: false,\n error: `Failed to create parent bead: ${parentResult.error}`,\n };\n }\n\n const childIds = new Map<string, string>();\n\n // Create child beads for each atom\n for (const atom of validated.atoms) {\n const childDescription = `Atom execution for workflow '${validated.workflow}'`;\n const childResult = await createBead(\n `[atomic] ${atom}`,\n childDescription,\n ['atomic', 'atom'],\n parentResult.id\n );\n\n if ('error' in childResult) {\n // Log warning but continue - partial tracking is better than none\n console.warn(`Warning: Failed to create bead for atom '${atom}': ${childResult.error}`);\n } else {\n childIds.set(atom, childResult.id);\n }\n }\n\n return {\n success: true,\n parentId: parentResult.id,\n childIds,\n };\n}\n\n/**\n * Build description for parent workflow bead.\n */\nfunction buildParentDescription(options: WorkflowBeadOptions): string {\n const lines: string[] = [];\n\n lines.push('## Workflow Execution');\n lines.push('');\n lines.push(`**Workflow:** \\`${options.workflow}\\``);\n if (options.description) {\n lines.push(`**Description:** ${options.description}`);\n }\n lines.push('');\n lines.push('## Atoms');\n lines.push('');\n for (const atom of options.atoms) {\n lines.push(`- [ ] ${atom}`);\n }\n lines.push('');\n lines.push('## Progress');\n lines.push('');\n lines.push('Child beads track individual atom status.');\n\n return lines.join('\\n');\n}\n\n/**\n * Update atom bead status.\n *\n * @param beadId - The bead ID to update\n * @param status - New status\n * @param details - Optional details (error message for failures)\n */\nexport async function updateAtomBead(\n beadId: string,\n status: AtomBeadStatus,\n details?: string\n): Promise<{ success: boolean; error?: string }> {\n const statusMap: Record<AtomBeadStatus, string> = {\n pending: 'todo',\n in_progress: 'in_progress',\n completed: 'done',\n failed: 'blocked',\n };\n\n const bdStatus = statusMap[status];\n const comment = details\n ? status === 'failed'\n ? `Failed: ${details}`\n : details\n : undefined;\n\n return updateBeadStatus(beadId, bdStatus, comment);\n}\n\n/**\n * Update parent workflow bead status.\n *\n * @param beadId - The parent bead ID\n * @param success - Whether workflow completed successfully\n * @param failedAtom - Name of failed atom (if any)\n */\nexport async function updateWorkflowBead(\n beadId: string,\n success: boolean,\n failedAtom?: string\n): Promise<{ success: boolean; error?: string }> {\n if (success) {\n return updateBeadStatus(beadId, 'done', 'Workflow completed successfully');\n } else {\n const comment = failedAtom\n ? `Blocked: Atom '${failedAtom}' failed`\n : 'Blocked: Workflow execution failed';\n return updateBeadStatus(beadId, 'blocked', comment);\n }\n}\n\n/**\n * Close a bead (mark as done).\n */\nexport async function closeBead(beadId: string): Promise<{ success: boolean; error?: string }> {\n return updateBeadStatus(beadId, 'done');\n}\n","/**\n * Run state management for workflow resumption.\n *\n * This module provides functions to save and load workflow run state,\n * enabling partial workflow resumption from the point of failure.\n *\n * @module workflow/run-state\n */\n\nimport { join } from 'node:path';\nimport { readFile, writeFile, mkdir, readdir } from 'node:fs/promises';\nimport { z } from 'zod';\nimport { ATOMIC_DIR, fileExists } from '../storage/index.js';\n\nconst RUNS_DIR = 'runs';\n\n/**\n * Schema for atom run state.\n */\nexport const AtomRunStateSchema = z.object({\n id: z.string().min(1),\n status: z.enum(['pending', 'running', 'completed', 'failed', 'skipped']),\n artifacts: z.array(z.string()).optional(),\n error: z.string().optional(),\n startedAt: z.string().optional(),\n completedAt: z.string().optional(),\n /** Bead ID for this atom's tracking issue */\n beadId: z.string().optional(),\n});\n\nexport type AtomRunState = z.infer<typeof AtomRunStateSchema>;\n\n/**\n * Schema for workflow run state.\n */\nexport const WorkflowRunStateSchema = z.object({\n runId: z.string().min(1),\n workflow: z.string().min(1),\n status: z.enum(['running', 'completed', 'failed', 'cancelled']),\n atoms: z.array(AtomRunStateSchema),\n executionOrder: z.array(z.string()),\n startedAt: z.string(),\n completedAt: z.string().optional(),\n failedAtom: z.string().optional(),\n error: z.string().optional(),\n /** Parent bead ID for workflow-level tracking */\n beadParentId: z.string().optional(),\n /** Whether beads tracking is enabled for this run */\n beadsEnabled: z.boolean().optional(),\n});\n\nexport type WorkflowRunState = z.infer<typeof WorkflowRunStateSchema>;\n\n/**\n * Generate a unique run ID.\n */\nexport function generateRunId(): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 8);\n return `run-${timestamp}-${random}`;\n}\n\n/**\n * Get the path to a run state file.\n */\nfunction getRunStatePath(runId: string): string {\n const projectRoot = process.cwd();\n return join(projectRoot, ATOMIC_DIR, RUNS_DIR, `${runId}.json`);\n}\n\n/**\n * Save workflow run state.\n *\n * @param state - The run state to save\n */\nexport async function saveRunState(state: WorkflowRunState): Promise<void> {\n const projectRoot = process.cwd();\n const runsDir = join(projectRoot, ATOMIC_DIR, RUNS_DIR);\n\n // Ensure runs directory exists\n await mkdir(runsDir, { recursive: true });\n\n const filePath = getRunStatePath(state.runId);\n await writeFile(filePath, JSON.stringify(state, null, 2), 'utf-8');\n}\n\n/**\n * Load workflow run state.\n *\n * @param runId - The run ID to load\n * @returns The run state, or null if not found\n */\nexport async function loadRunState(\n runId: string\n): Promise<WorkflowRunState | null> {\n const filePath = getRunStatePath(runId);\n\n if (!(await fileExists(filePath))) {\n return null;\n }\n\n try {\n const content = await readFile(filePath, 'utf-8');\n const data = JSON.parse(content);\n return WorkflowRunStateSchema.parse(data);\n } catch (_err) {\n // File exists but is invalid (JSON parse error or schema validation failure)\n // Optionally log for debugging: console.warn(`Failed to load run state ${runId}:`, err);\n return null;\n }\n}\n\n/**\n * List all run states for a workflow.\n *\n * @param workflowName - The workflow name to filter by (optional)\n * @returns Array of run states\n */\nexport async function listRunStates(\n workflowName?: string\n): Promise<WorkflowRunState[]> {\n const projectRoot = process.cwd();\n const runsDir = join(projectRoot, ATOMIC_DIR, RUNS_DIR);\n\n if (!(await fileExists(runsDir))) {\n return [];\n }\n\n const files = await readdir(runsDir);\n const runFiles = files.filter((f) => f.endsWith('.json'));\n\n const states: WorkflowRunState[] = [];\n for (const file of runFiles) {\n const runId = file.replace('.json', '');\n const state = await loadRunState(runId);\n if (state) {\n if (!workflowName || state.workflow === workflowName) {\n states.push(state);\n }\n }\n }\n\n // Sort by startedAt descending (most recent first)\n states.sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime());\n\n return states;\n}\n\n/**\n * Options for bead tracking in run state.\n */\nexport interface BeadOptions {\n /** Whether beads tracking is enabled */\n enabled: boolean;\n /** Parent bead ID for workflow-level tracking */\n parentId?: string;\n /** Map of atom IDs to their bead IDs */\n atomBeadIds?: Map<string, string>;\n}\n\n/**\n * Create initial run state for a workflow.\n *\n * @param workflow - Workflow name\n * @param executionOrder - Ordered list of atom IDs\n * @param skipped - List of skipped atom IDs\n * @param beadOptions - Optional bead tracking options\n */\nexport function createRunState(\n workflow: string,\n executionOrder: string[],\n skipped: string[],\n beadOptions?: BeadOptions\n): WorkflowRunState {\n const runId = generateRunId();\n const now = new Date().toISOString();\n\n const atoms: AtomRunState[] = executionOrder.map((id) => ({\n id,\n status: skipped.includes(id) ? 'skipped' : 'pending',\n beadId: beadOptions?.atomBeadIds?.get(id),\n }));\n\n return {\n runId,\n workflow,\n status: 'running',\n atoms,\n executionOrder,\n startedAt: now,\n beadsEnabled: beadOptions?.enabled ?? false,\n beadParentId: beadOptions?.parentId,\n };\n}\n\n/** WeakMap cache for atom index lookups, keyed by run state object. */\nconst atomIndexCache = new WeakMap<WorkflowRunState, Map<string, AtomRunState>>();\n\n/**\n * Update atom state in a run.\n *\n * @param state - The run state to update\n * @param atomId - The atom ID\n * @param updates - The updates to apply\n * @throws Error if atomId is not found in the run state\n */\nexport function updateAtomState(\n state: WorkflowRunState,\n atomId: string,\n updates: Partial<AtomRunState>\n): void {\n // Build index on first call or when atoms array changes length\n let index = atomIndexCache.get(state);\n if (!index || index.size !== state.atoms.length) {\n index = new Map<string, AtomRunState>();\n for (const atom of state.atoms) {\n index.set(atom.id, atom);\n }\n atomIndexCache.set(state, index);\n }\n\n let atom = index.get(atomId);\n if (!atom) {\n // Rebuild once on cache miss (handles same-length array replacement)\n index = new Map(state.atoms.map((a) => [a.id, a]));\n atomIndexCache.set(state, index);\n atom = index.get(atomId);\n }\n if (!atom) {\n throw new Error(`Atom '${atomId}' not found in run state for workflow '${state.workflow}'`);\n }\n Object.assign(atom, updates);\n}\n\n/**\n * Get atoms that need to be executed for resumption.\n *\n * @param state - The run state\n * @param fromAtom - Optional atom to restart from\n * @returns List of atom IDs to execute\n */\nexport function getResumableAtoms(\n state: WorkflowRunState,\n fromAtom?: string\n): string[] {\n const executionOrder = state.executionOrder;\n\n // If --from is specified, find the starting point\n if (fromAtom) {\n const startIndex = executionOrder.indexOf(fromAtom);\n if (startIndex === -1) {\n throw new Error(`Atom '${fromAtom}' not found in workflow`);\n }\n // Return all atoms from the specified point onwards\n return executionOrder.slice(startIndex);\n }\n\n // Build index for O(1) lookups\n const atomMap = new Map<string, AtomRunState>();\n for (const atom of state.atoms) {\n atomMap.set(atom.id, atom);\n }\n\n // Find first non-completed atom\n const toExecute: string[] = [];\n let foundIncomplete = false;\n\n for (const id of executionOrder) {\n const atom = atomMap.get(id);\n // Include 'running' as incomplete - process may have been killed mid-execution\n if (!atom || atom.status === 'pending' || atom.status === 'failed' || atom.status === 'running') {\n foundIncomplete = true;\n }\n\n if (foundIncomplete) {\n toExecute.push(id);\n }\n }\n\n return toExecute;\n}\n\n/**\n * Get the last failed run for a workflow.\n *\n * @param workflowName - The workflow name\n * @returns The most recent failed run state, or null\n */\nexport async function getLastFailedRun(\n workflowName: string\n): Promise<WorkflowRunState | null> {\n const states = await listRunStates(workflowName);\n return states.find((s) => s.status === 'failed') ?? null;\n}\n"],"mappings":"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","names":["z","z","z","z","atom"]}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import {
|
|
2
|
+
toErrorMessage
|
|
3
|
+
} from "./chunk-PLQJM2KT.js";
|
|
4
|
+
|
|
5
|
+
// src/schemas/trust.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var TrustLevel = z.enum(["new", "proven", "trusted"]);
|
|
8
|
+
var TrustMetadata = z.object({
|
|
9
|
+
/** Current trust level */
|
|
10
|
+
level: TrustLevel,
|
|
11
|
+
/** Number of successful executions since last change */
|
|
12
|
+
successCount: z.number().int().min(0).default(0),
|
|
13
|
+
/** Number of corrections since last promotion */
|
|
14
|
+
correctionCount: z.number().int().min(0).default(0),
|
|
15
|
+
/** When the trust level was last changed */
|
|
16
|
+
lastChanged: z.iso.datetime().describe("ISO timestamp"),
|
|
17
|
+
/** Reason for last trust change (if any) */
|
|
18
|
+
reason: z.string().optional()
|
|
19
|
+
});
|
|
20
|
+
var StackTrust = z.object({
|
|
21
|
+
/** Stack name (must be non-empty) */
|
|
22
|
+
stack: z.string().min(1),
|
|
23
|
+
/** Trust metadata */
|
|
24
|
+
trust: TrustMetadata
|
|
25
|
+
});
|
|
26
|
+
var TrustFile = z.object({
|
|
27
|
+
/** Schema version for future migrations */
|
|
28
|
+
version: z.literal(1),
|
|
29
|
+
/** Default trust level for new stacks */
|
|
30
|
+
defaultLevel: TrustLevel.default("new"),
|
|
31
|
+
/** Trust data for individual stacks */
|
|
32
|
+
stacks: z.record(z.string(), TrustMetadata),
|
|
33
|
+
/** Promotion thresholds */
|
|
34
|
+
thresholds: z.object({
|
|
35
|
+
/** Successes needed to suggest new → proven */
|
|
36
|
+
newToProven: z.number().int().min(1).default(3),
|
|
37
|
+
/** Successes needed to suggest proven → trusted */
|
|
38
|
+
provenToTrusted: z.number().int().min(1).default(5),
|
|
39
|
+
/** Corrections to trigger proven → new */
|
|
40
|
+
provenToNew: z.number().int().min(1).default(2)
|
|
41
|
+
}).default({
|
|
42
|
+
newToProven: 3,
|
|
43
|
+
provenToTrusted: 5,
|
|
44
|
+
provenToNew: 2
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
function createTrustFile() {
|
|
48
|
+
return TrustFile.parse({
|
|
49
|
+
version: 1,
|
|
50
|
+
stacks: {}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function migrateTrustData(raw) {
|
|
54
|
+
if ("capabilities" in raw && !("stacks" in raw)) {
|
|
55
|
+
const { capabilities, ...rest } = raw;
|
|
56
|
+
return { ...rest, stacks: capabilities };
|
|
57
|
+
}
|
|
58
|
+
return raw;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/schemas/registry.ts
|
|
62
|
+
import { z as z2 } from "zod";
|
|
63
|
+
var RegistryAtom = z2.object({
|
|
64
|
+
name: z2.string().regex(/^[a-z][a-z0-9_]*$/, "Name must be snake_case"),
|
|
65
|
+
description: z2.string().min(1),
|
|
66
|
+
path: z2.string().describe("Path to the atom file"),
|
|
67
|
+
idempotent: z2.boolean(),
|
|
68
|
+
tests: z2.object({ path: z2.string() }),
|
|
69
|
+
agent: z2.string().optional(),
|
|
70
|
+
skill: z2.string().optional(),
|
|
71
|
+
/** Multi-skill support */
|
|
72
|
+
skills: z2.array(z2.string()).optional(),
|
|
73
|
+
registeredAt: z2.string().describe("ISO timestamp of registration"),
|
|
74
|
+
/** JSON Schema for input (generated from Zod on register) */
|
|
75
|
+
inputSchema: z2.looseObject({}).describe("JSON Schema for input"),
|
|
76
|
+
/** JSON Schema for output (generated from Zod on register) */
|
|
77
|
+
outputSchema: z2.looseObject({}).describe("JSON Schema for output"),
|
|
78
|
+
/** SHA-256 hash of atom file content at registration time */
|
|
79
|
+
contentHash: z2.string().regex(/^[a-f0-9]{64}$/, "contentHash must be a valid SHA-256 hex string").optional(),
|
|
80
|
+
/** Whether this atom has been graduated to a generator */
|
|
81
|
+
graduated: z2.boolean().default(false),
|
|
82
|
+
/** Path to the generator file (set when graduated = true) */
|
|
83
|
+
generatorPath: z2.string().optional(),
|
|
84
|
+
/** ISO timestamp of graduation */
|
|
85
|
+
graduatedAt: z2.string().optional()
|
|
86
|
+
});
|
|
87
|
+
var RegistryFile = z2.object({
|
|
88
|
+
atoms: z2.record(z2.string(), RegistryAtom)
|
|
89
|
+
});
|
|
90
|
+
function graduateAtom(atom, generatorPath) {
|
|
91
|
+
return RegistryAtom.parse({
|
|
92
|
+
...atom,
|
|
93
|
+
graduated: true,
|
|
94
|
+
generatorPath,
|
|
95
|
+
graduatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function revertAtom(atom) {
|
|
99
|
+
const { generatorPath: _, graduatedAt: __, ...rest } = atom;
|
|
100
|
+
return RegistryAtom.parse({
|
|
101
|
+
...rest,
|
|
102
|
+
graduated: false,
|
|
103
|
+
generatorPath: void 0,
|
|
104
|
+
graduatedAt: void 0
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/storage/index.ts
|
|
109
|
+
import { connect } from "@tursodatabase/database";
|
|
110
|
+
import { mkdir, writeFile, readFile, access, rename, unlink } from "fs/promises";
|
|
111
|
+
import { join } from "path";
|
|
112
|
+
|
|
113
|
+
// src/storage/runs.ts
|
|
114
|
+
import { randomUUID, createHash } from "crypto";
|
|
115
|
+
async function createRun(projectRoot, atomName, input, workflowId) {
|
|
116
|
+
const runId = randomUUID();
|
|
117
|
+
const inputHash = createHash("sha256").update(JSON.stringify(input)).digest("hex").substring(0, 16);
|
|
118
|
+
const db = await getClient(projectRoot);
|
|
119
|
+
try {
|
|
120
|
+
await db.prepare(
|
|
121
|
+
`INSERT INTO runs (id, atom_name, workflow_id, input_hash, status, started_at)
|
|
122
|
+
VALUES (?, ?, ?, ?, 'running', datetime('now'))`
|
|
123
|
+
).run(runId, atomName, workflowId ?? null, inputHash);
|
|
124
|
+
return runId;
|
|
125
|
+
} finally {
|
|
126
|
+
await db.close();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function completeRun(projectRoot, runId, status, errorMessage) {
|
|
130
|
+
const db = await getClient(projectRoot);
|
|
131
|
+
try {
|
|
132
|
+
await db.prepare(
|
|
133
|
+
`UPDATE runs SET status = ?, completed_at = datetime('now'), error_message = ?
|
|
134
|
+
WHERE id = ?`
|
|
135
|
+
).run(status, errorMessage ?? null, runId);
|
|
136
|
+
} finally {
|
|
137
|
+
await db.close();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/storage/index.ts
|
|
142
|
+
var ATOMIC_DIR = ".atomic";
|
|
143
|
+
var DB_FILE = "storage.db";
|
|
144
|
+
var REGISTRY_FILE = "registry.json";
|
|
145
|
+
var TRUST_FILE = "trust.json";
|
|
146
|
+
var MIGRATIONS = [
|
|
147
|
+
// Content-addressed object storage
|
|
148
|
+
`CREATE TABLE IF NOT EXISTS objects (
|
|
149
|
+
hash TEXT PRIMARY KEY,
|
|
150
|
+
content BLOB NOT NULL,
|
|
151
|
+
content_type TEXT NOT NULL,
|
|
152
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
153
|
+
)`,
|
|
154
|
+
// Run manifests (like git commits)
|
|
155
|
+
`CREATE TABLE IF NOT EXISTS runs (
|
|
156
|
+
id TEXT PRIMARY KEY,
|
|
157
|
+
atom_name TEXT NOT NULL,
|
|
158
|
+
workflow_id TEXT,
|
|
159
|
+
input_hash TEXT NOT NULL,
|
|
160
|
+
started_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
161
|
+
completed_at TEXT,
|
|
162
|
+
status TEXT NOT NULL,
|
|
163
|
+
error_message TEXT
|
|
164
|
+
)`,
|
|
165
|
+
// Run to artifact mapping
|
|
166
|
+
`CREATE TABLE IF NOT EXISTS run_artifacts (
|
|
167
|
+
run_id TEXT NOT NULL,
|
|
168
|
+
artifact_path TEXT NOT NULL,
|
|
169
|
+
object_hash TEXT NOT NULL,
|
|
170
|
+
PRIMARY KEY (run_id, artifact_path),
|
|
171
|
+
FOREIGN KEY (run_id) REFERENCES runs(id),
|
|
172
|
+
FOREIGN KEY (object_hash) REFERENCES objects(hash)
|
|
173
|
+
)`,
|
|
174
|
+
// Latest artifact pointers (working directory)
|
|
175
|
+
`CREATE TABLE IF NOT EXISTS latest (
|
|
176
|
+
artifact_path TEXT PRIMARY KEY,
|
|
177
|
+
object_hash TEXT NOT NULL,
|
|
178
|
+
run_id TEXT NOT NULL,
|
|
179
|
+
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
180
|
+
FOREIGN KEY (object_hash) REFERENCES objects(hash),
|
|
181
|
+
FOREIGN KEY (run_id) REFERENCES runs(id)
|
|
182
|
+
)`,
|
|
183
|
+
// Schema version tracking
|
|
184
|
+
`CREATE TABLE IF NOT EXISTS schema_version (
|
|
185
|
+
version INTEGER PRIMARY KEY,
|
|
186
|
+
applied_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
187
|
+
)`
|
|
188
|
+
];
|
|
189
|
+
var CURRENT_SCHEMA_VERSION = 1;
|
|
190
|
+
var StorageNotInitializedError = class extends Error {
|
|
191
|
+
constructor() {
|
|
192
|
+
super("Storage not initialized. Run `atomic init` first.");
|
|
193
|
+
this.name = "StorageNotInitializedError";
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
async function fileExists(path) {
|
|
197
|
+
try {
|
|
198
|
+
await access(path);
|
|
199
|
+
return true;
|
|
200
|
+
} catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async function initStorage(projectRoot) {
|
|
205
|
+
const atomicDir = join(projectRoot, ATOMIC_DIR);
|
|
206
|
+
const dbPath = join(atomicDir, DB_FILE);
|
|
207
|
+
const registryPath = join(atomicDir, REGISTRY_FILE);
|
|
208
|
+
const trustPath = join(atomicDir, TRUST_FILE);
|
|
209
|
+
const dirExisted = await fileExists(atomicDir);
|
|
210
|
+
await mkdir(atomicDir, { recursive: true });
|
|
211
|
+
const db = await connect(dbPath);
|
|
212
|
+
let migrationsRun = 0;
|
|
213
|
+
try {
|
|
214
|
+
await db.exec("PRAGMA foreign_keys = ON");
|
|
215
|
+
for (const migration of MIGRATIONS) {
|
|
216
|
+
await db.exec(migration);
|
|
217
|
+
migrationsRun++;
|
|
218
|
+
}
|
|
219
|
+
await db.prepare("INSERT OR IGNORE INTO schema_version (version) VALUES (?)").run(CURRENT_SCHEMA_VERSION);
|
|
220
|
+
} finally {
|
|
221
|
+
await db.close();
|
|
222
|
+
}
|
|
223
|
+
if (!await fileExists(registryPath)) {
|
|
224
|
+
await writeFile(
|
|
225
|
+
registryPath,
|
|
226
|
+
JSON.stringify({ atoms: {} }, null, 2)
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
if (!await fileExists(trustPath)) {
|
|
230
|
+
await writeFile(trustPath, JSON.stringify(createTrustFile(), null, 2));
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
created: !dirExisted,
|
|
234
|
+
path: atomicDir,
|
|
235
|
+
dbPath,
|
|
236
|
+
migrationsRun
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
async function getClient(projectRoot) {
|
|
240
|
+
const dbPath = join(projectRoot, ATOMIC_DIR, DB_FILE);
|
|
241
|
+
if (!await fileExists(dbPath)) {
|
|
242
|
+
throw new StorageNotInitializedError();
|
|
243
|
+
}
|
|
244
|
+
const db = await connect(dbPath);
|
|
245
|
+
try {
|
|
246
|
+
await db.exec("PRAGMA foreign_keys = ON");
|
|
247
|
+
return db;
|
|
248
|
+
} catch (err) {
|
|
249
|
+
await db.close();
|
|
250
|
+
throw err;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async function loadRegistry(registryPath) {
|
|
254
|
+
if (!await fileExists(registryPath)) {
|
|
255
|
+
throw new StorageNotInitializedError();
|
|
256
|
+
}
|
|
257
|
+
const content = await readFile(registryPath, "utf-8");
|
|
258
|
+
let data;
|
|
259
|
+
try {
|
|
260
|
+
data = JSON.parse(content);
|
|
261
|
+
} catch (err) {
|
|
262
|
+
throw new Error(`Invalid JSON in registry file: ${toErrorMessage(err)}`);
|
|
263
|
+
}
|
|
264
|
+
if (data != null && typeof data === "object" && "capabilities" in data) {
|
|
265
|
+
delete data["capabilities"];
|
|
266
|
+
}
|
|
267
|
+
return RegistryFile.parse(data);
|
|
268
|
+
}
|
|
269
|
+
async function saveRegistry(registryPath, registry) {
|
|
270
|
+
const tempPath = `${registryPath}.tmp`;
|
|
271
|
+
try {
|
|
272
|
+
await writeFile(tempPath, JSON.stringify(registry, null, 2));
|
|
273
|
+
await rename(tempPath, registryPath);
|
|
274
|
+
} catch (err) {
|
|
275
|
+
try {
|
|
276
|
+
await unlink(tempPath);
|
|
277
|
+
} catch {
|
|
278
|
+
}
|
|
279
|
+
throw err;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
function getRegistryPath(projectRoot) {
|
|
283
|
+
return join(projectRoot, ATOMIC_DIR, REGISTRY_FILE);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export {
|
|
287
|
+
TrustLevel,
|
|
288
|
+
TrustFile,
|
|
289
|
+
createTrustFile,
|
|
290
|
+
migrateTrustData,
|
|
291
|
+
RegistryFile,
|
|
292
|
+
graduateAtom,
|
|
293
|
+
revertAtom,
|
|
294
|
+
createRun,
|
|
295
|
+
completeRun,
|
|
296
|
+
ATOMIC_DIR,
|
|
297
|
+
DB_FILE,
|
|
298
|
+
REGISTRY_FILE,
|
|
299
|
+
TRUST_FILE,
|
|
300
|
+
StorageNotInitializedError,
|
|
301
|
+
fileExists,
|
|
302
|
+
initStorage,
|
|
303
|
+
getClient,
|
|
304
|
+
loadRegistry,
|
|
305
|
+
saveRegistry,
|
|
306
|
+
getRegistryPath
|
|
307
|
+
};
|
|
308
|
+
//# sourceMappingURL=chunk-YKJO3ZFY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schemas/trust.ts","../src/schemas/registry.ts","../src/storage/index.ts","../src/storage/runs.ts"],"sourcesContent":["/**\n * Trust level schemas for the atomic framework.\n *\n * Trust levels control execution oversight:\n * - `new`: Human review required before execution\n * - `proven`: Human review optional (prompted but skippable)\n * - `trusted`: Auto-execute without review\n *\n * @module schemas/trust\n */\n\nimport { z } from 'zod';\n\n/**\n * Trust levels in ascending order of autonomy.\n *\n * - new: Requires human review before execution\n * - proven: Review is optional (prompted but skippable)\n * - trusted: Auto-executes without prompts\n */\nexport const TrustLevel = z.enum(['new', 'proven', 'trusted']);\nexport type TrustLevel = z.infer<typeof TrustLevel>;\n\n/**\n * Trust level metadata for an atom stack.\n */\nexport const TrustMetadata = z.object({\n /** Current trust level */\n level: TrustLevel,\n /** Number of successful executions since last change */\n successCount: z.number().int().min(0).default(0),\n /** Number of corrections since last promotion */\n correctionCount: z.number().int().min(0).default(0),\n /** When the trust level was last changed */\n lastChanged: z.iso.datetime().describe('ISO timestamp'),\n /** Reason for last trust change (if any) */\n reason: z.string().optional(),\n});\nexport type TrustMetadata = z.infer<typeof TrustMetadata>;\n\n/**\n * Trust entry for a single atom stack.\n */\nexport const StackTrust = z.object({\n /** Stack name (must be non-empty) */\n stack: z.string().min(1),\n /** Trust metadata */\n trust: TrustMetadata,\n});\nexport type StackTrust = z.infer<typeof StackTrust>;\n\n/** @deprecated Use StackTrust instead. */\nexport const CapabilityTrust = StackTrust;\n/** @deprecated Use StackTrust instead. */\nexport type CapabilityTrust = StackTrust;\n\n/**\n * Trust file structure for .atomic/trust.json\n */\nexport const TrustFile = z.object({\n /** Schema version for future migrations */\n version: z.literal(1),\n /** Default trust level for new stacks */\n defaultLevel: TrustLevel.default('new'),\n /** Trust data for individual stacks */\n stacks: z.record(z.string(), TrustMetadata),\n /** Promotion thresholds */\n thresholds: z.object({\n /** Successes needed to suggest new → proven */\n newToProven: z.number().int().min(1).default(3),\n /** Successes needed to suggest proven → trusted */\n provenToTrusted: z.number().int().min(1).default(5),\n /** Corrections to trigger proven → new */\n provenToNew: z.number().int().min(1).default(2),\n }).default({\n newToProven: 3,\n provenToTrusted: 5,\n provenToNew: 2,\n }),\n});\nexport type TrustFile = z.infer<typeof TrustFile>;\n\n/**\n * Create default trust metadata for a new stack.\n */\nexport function createDefaultTrust(level: TrustLevel = 'new'): TrustMetadata {\n return TrustMetadata.parse({\n level,\n successCount: 0,\n correctionCount: 0,\n lastChanged: new Date().toISOString(),\n });\n}\n\n/**\n * Create an empty trust file with defaults.\n */\nexport function createTrustFile(): TrustFile {\n return TrustFile.parse({\n version: 1,\n stacks: {},\n });\n}\n\n/**\n * Migrate raw trust data from the old `capabilities` key to the new `stacks` key.\n *\n * If the data has `capabilities` but no `stacks`, moves the data over.\n * Returns the migrated object (does not mutate the input).\n */\nexport function migrateTrustData(raw: Record<string, unknown>): Record<string, unknown> {\n if ('capabilities' in raw && !('stacks' in raw)) {\n const { capabilities, ...rest } = raw;\n return { ...rest, stacks: capabilities };\n }\n return raw;\n}\n\n/**\n * Get the numeric order of a trust level (for comparisons).\n * Higher number = more trusted.\n */\nexport function trustOrder(level: TrustLevel): number {\n switch (level) {\n case 'new':\n return 0;\n case 'proven':\n return 1;\n case 'trusted':\n return 2;\n default: {\n const _exhaustive: never = level;\n throw new Error(`Unknown trust level: ${_exhaustive}`);\n }\n }\n}\n\n/**\n * Check if level A is at least as trusted as level B.\n */\nexport function isAtLeast(a: TrustLevel, b: TrustLevel): boolean {\n return trustOrder(a) >= trustOrder(b);\n}\n","import { z } from \"zod\";\n\n/**\n * Registry atom entry - the unified unit of execution in atomism.\n *\n * An atom can be either:\n * - Handler-based (probabilistic): runs the atom's handler function\n * - Generator-based (deterministic): runs a graduated generator template\n *\n * Graduation happens directly on atoms - no separate capability layer needed.\n */\nexport const RegistryAtom = z.object({\n name: z.string().regex(/^[a-z][a-z0-9_]*$/, \"Name must be snake_case\"),\n description: z.string().min(1),\n path: z.string().describe(\"Path to the atom file\"),\n idempotent: z.boolean(),\n tests: z.object({ path: z.string() }),\n agent: z.string().optional(),\n skill: z.string().optional(),\n /** Multi-skill support */\n skills: z.array(z.string()).optional(),\n registeredAt: z.string().describe(\"ISO timestamp of registration\"),\n /** JSON Schema for input (generated from Zod on register) */\n inputSchema: z.looseObject({}).describe(\"JSON Schema for input\"),\n /** JSON Schema for output (generated from Zod on register) */\n outputSchema: z.looseObject({}).describe(\"JSON Schema for output\"),\n /** SHA-256 hash of atom file content at registration time */\n contentHash: z.string().regex(/^[a-f0-9]{64}$/, 'contentHash must be a valid SHA-256 hex string').optional(),\n /** Whether this atom has been graduated to a generator */\n graduated: z.boolean().default(false),\n /** Path to the generator file (set when graduated = true) */\n generatorPath: z.string().optional(),\n /** ISO timestamp of graduation */\n graduatedAt: z.string().optional(),\n});\nexport type RegistryAtom = z.infer<typeof RegistryAtom>;\n\n/**\n * Registry file structure for .atomic/registry.json\n *\n * The registry contains only atoms - no separate capabilities section.\n * Atoms are workflow-composable by default after registration.\n */\nexport const RegistryFile = z.object({\n atoms: z.record(z.string(), RegistryAtom),\n});\nexport type RegistryFile = z.infer<typeof RegistryFile>;\n\n/**\n * Create a new atom registry entry with defaults.\n */\nexport function createRegistryAtom(config: {\n name: string;\n description: string;\n path: string;\n idempotent: boolean;\n tests: { path: string };\n inputSchema: Record<string, unknown>;\n outputSchema: Record<string, unknown>;\n agent?: string;\n skill?: string;\n skills?: string[];\n}): RegistryAtom {\n return RegistryAtom.parse({\n ...config,\n registeredAt: new Date().toISOString(),\n graduated: false,\n });\n}\n\n/**\n * Graduate an atom to a generator.\n * Returns a new atom entry with graduation fields set.\n */\nexport function graduateAtom(\n atom: RegistryAtom,\n generatorPath: string,\n): RegistryAtom {\n return RegistryAtom.parse({\n ...atom,\n graduated: true,\n generatorPath,\n graduatedAt: new Date().toISOString(),\n });\n}\n\n/**\n * Revert an atom from generator back to handler.\n * Returns a new atom entry with graduation fields cleared.\n */\nexport function revertAtom(atom: RegistryAtom): RegistryAtom {\n const { generatorPath: _, graduatedAt: __, ...rest } = atom;\n return RegistryAtom.parse({\n ...rest,\n graduated: false,\n generatorPath: undefined,\n graduatedAt: undefined,\n });\n}\n","import { connect } from '@tursodatabase/database';\nimport { mkdir, writeFile, readFile, access, rename, unlink } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { createTrustFile } from '../schemas/trust.js';\nimport { RegistryFile } from '../schemas/registry.js';\nimport { toErrorMessage } from '../utils/errors.js';\n\nconst ATOMIC_DIR = '.atomic';\nconst DB_FILE = 'storage.db';\nconst REGISTRY_FILE = 'registry.json';\nconst TRUST_FILE = 'trust.json';\n\n// Database migrations - executed in order\nconst MIGRATIONS = [\n // Content-addressed object storage\n `CREATE TABLE IF NOT EXISTS objects (\n hash TEXT PRIMARY KEY,\n content BLOB NOT NULL,\n content_type TEXT NOT NULL,\n created_at TEXT DEFAULT CURRENT_TIMESTAMP\n )`,\n\n // Run manifests (like git commits)\n `CREATE TABLE IF NOT EXISTS runs (\n id TEXT PRIMARY KEY,\n atom_name TEXT NOT NULL,\n workflow_id TEXT,\n input_hash TEXT NOT NULL,\n started_at TEXT DEFAULT CURRENT_TIMESTAMP,\n completed_at TEXT,\n status TEXT NOT NULL,\n error_message TEXT\n )`,\n\n // Run to artifact mapping\n `CREATE TABLE IF NOT EXISTS run_artifacts (\n run_id TEXT NOT NULL,\n artifact_path TEXT NOT NULL,\n object_hash TEXT NOT NULL,\n PRIMARY KEY (run_id, artifact_path),\n FOREIGN KEY (run_id) REFERENCES runs(id),\n FOREIGN KEY (object_hash) REFERENCES objects(hash)\n )`,\n\n // Latest artifact pointers (working directory)\n `CREATE TABLE IF NOT EXISTS latest (\n artifact_path TEXT PRIMARY KEY,\n object_hash TEXT NOT NULL,\n run_id TEXT NOT NULL,\n updated_at TEXT DEFAULT CURRENT_TIMESTAMP,\n FOREIGN KEY (object_hash) REFERENCES objects(hash),\n FOREIGN KEY (run_id) REFERENCES runs(id)\n )`,\n\n // Schema version tracking\n `CREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY,\n applied_at TEXT DEFAULT CURRENT_TIMESTAMP\n )`,\n];\n\nconst CURRENT_SCHEMA_VERSION = 1;\n\n/**\n * Thrown when an operation requires initialized storage that doesn't exist.\n */\nexport class StorageNotInitializedError extends Error {\n constructor() {\n super('Storage not initialized. Run `atomic init` first.');\n this.name = 'StorageNotInitializedError';\n }\n}\n\nexport interface InitResult {\n created: boolean;\n path: string;\n dbPath: string;\n migrationsRun: number;\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Initialize the .atomic storage directory, database, and config files.\n */\nexport async function initStorage(projectRoot: string): Promise<InitResult> {\n const atomicDir = join(projectRoot, ATOMIC_DIR);\n const dbPath = join(atomicDir, DB_FILE);\n const registryPath = join(atomicDir, REGISTRY_FILE);\n const trustPath = join(atomicDir, TRUST_FILE);\n\n const dirExisted = await fileExists(atomicDir);\n\n // Create .atomic directory\n await mkdir(atomicDir, { recursive: true });\n\n // Initialize database\n const db = await connect(dbPath);\n\n let migrationsRun = 0;\n try {\n // Enable foreign key enforcement (SQLite has it OFF by default)\n await db.exec('PRAGMA foreign_keys = ON');\n\n // Run migrations\n for (const migration of MIGRATIONS) {\n await db.exec(migration);\n migrationsRun++;\n }\n\n // Record schema version (idempotent)\n await db.prepare('INSERT OR IGNORE INTO schema_version (version) VALUES (?)').run(CURRENT_SCHEMA_VERSION);\n } finally {\n await db.close();\n }\n\n // Initialize registry.json (if not exists)\n if (!(await fileExists(registryPath))) {\n await writeFile(\n registryPath,\n JSON.stringify({ atoms: {} }, null, 2)\n );\n }\n\n // Initialize trust.json (if not exists)\n if (!(await fileExists(trustPath))) {\n await writeFile(trustPath, JSON.stringify(createTrustFile(), null, 2));\n }\n\n return {\n created: !dirExisted,\n path: atomicDir,\n dbPath,\n migrationsRun,\n };\n}\n\n/** Type alias for the database handle returned by connect(). */\nexport type Database = Awaited<ReturnType<typeof connect>>;\n\n/**\n * Open a database connection for the project's .atomic database.\n */\nexport async function getClient(projectRoot: string): Promise<Database> {\n const dbPath = join(projectRoot, ATOMIC_DIR, DB_FILE);\n\n if (!(await fileExists(dbPath))) {\n throw new StorageNotInitializedError();\n }\n\n const db = await connect(dbPath);\n\n try {\n // Enable foreign key enforcement (SQLite has it OFF by default, per-connection)\n await db.exec('PRAGMA foreign_keys = ON');\n return db;\n } catch (err) {\n await db.close();\n throw err;\n }\n}\n\n/**\n * Load and validate the atom registry from disk.\n *\n * Handles migration from the deprecated `capabilities` format and\n * validates the result with the RegistryFile Zod schema.\n *\n * @param registryPath - Absolute path to the registry.json file\n * @returns Validated registry data\n * @throws Error if the file doesn't exist, contains invalid JSON, or fails validation\n */\nexport async function loadRegistry(registryPath: string): Promise<RegistryFile> {\n if (!(await fileExists(registryPath))) {\n throw new StorageNotInitializedError();\n }\n\n const content = await readFile(registryPath, 'utf-8');\n let data: unknown;\n try {\n data = JSON.parse(content);\n } catch (err) {\n throw new Error(`Invalid JSON in registry file: ${toErrorMessage(err)}`);\n }\n\n // Migration: remove deprecated 'capabilities' key from old format\n if (data != null && typeof data === 'object' && 'capabilities' in data) {\n delete (data as Record<string, unknown>)['capabilities'];\n }\n\n return RegistryFile.parse(data);\n}\n\n/**\n * Atomically write the registry to disk (temp file + rename).\n */\nexport async function saveRegistry(registryPath: string, registry: RegistryFile): Promise<void> {\n const tempPath = `${registryPath}.tmp`;\n try {\n await writeFile(tempPath, JSON.stringify(registry, null, 2));\n await rename(tempPath, registryPath);\n } catch (err) {\n try { await unlink(tempPath); } catch { /* ignore cleanup errors */ }\n throw err;\n }\n}\n\n/**\n * Build the absolute path to a project's registry.json file.\n */\nexport function getRegistryPath(projectRoot: string): string {\n return join(projectRoot, ATOMIC_DIR, REGISTRY_FILE);\n}\n\nexport { ATOMIC_DIR, DB_FILE, REGISTRY_FILE, TRUST_FILE, fileExists };\nexport { createRun, completeRun } from './runs.js';\n","/**\n * Run persistence helpers for the atomic CLI.\n *\n * Provides functions to create and complete run records in the database,\n * enabling `atomic history` to display execution history.\n *\n * @module storage/runs\n */\n\nimport { randomUUID, createHash } from 'node:crypto';\nimport { getClient } from './index.js';\n\n/**\n * Create a new run record with 'running' status.\n *\n * @param projectRoot - Project root directory (for database location)\n * @param atomName - Name of the atom being executed\n * @param input - Input data for hashing\n * @param workflowId - Optional workflow ID if this run is part of a workflow\n * @returns The generated run ID\n */\nexport async function createRun(\n projectRoot: string,\n atomName: string,\n input: unknown,\n workflowId?: string\n): Promise<string> {\n const runId = randomUUID();\n const inputHash = createHash('sha256')\n .update(JSON.stringify(input))\n .digest('hex')\n .substring(0, 16);\n\n const db = await getClient(projectRoot);\n try {\n await db.prepare(\n `INSERT INTO runs (id, atom_name, workflow_id, input_hash, status, started_at)\n VALUES (?, ?, ?, ?, 'running', datetime('now'))`\n ).run(runId, atomName, workflowId ?? null, inputHash);\n return runId;\n } finally {\n await db.close();\n }\n}\n\n/**\n * Mark a run as completed (success or error).\n *\n * @param projectRoot - Project root directory (for database location)\n * @param runId - The run ID to update\n * @param status - Final status: 'success' or 'error'\n * @param errorMessage - Optional error message if status is 'error'\n */\nexport async function completeRun(\n projectRoot: string,\n runId: string,\n status: 'success' | 'error',\n errorMessage?: string\n): Promise<void> {\n const db = await getClient(projectRoot);\n try {\n await db.prepare(\n `UPDATE runs SET status = ?, completed_at = datetime('now'), error_message = ?\n WHERE id = ?`\n ).run(status, errorMessage ?? null, runId);\n } finally {\n await db.close();\n }\n}\n"],"mappings":"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","names":["z"]}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
var program = new Command();
|
|
6
|
+
program.name("atomic").description("Schema-first agent swarm orchestration framework").version("0.1.0");
|
|
7
|
+
program.command("init").description("Initialize .atomic/ directory with storage and registry").option("--json", "Output structured JSON response").action(async (options) => {
|
|
8
|
+
const { initCommand } = await import("./init-2FINDMYK.js");
|
|
9
|
+
return initCommand(options);
|
|
10
|
+
});
|
|
11
|
+
program.command("register <path>").description("Register an atom file").option("--json", "Output structured JSON response").action(async (atomPath, options) => {
|
|
12
|
+
const { registerCommand } = await import("./register-XTRMSH7Y.js");
|
|
13
|
+
return registerCommand(atomPath, options);
|
|
14
|
+
});
|
|
15
|
+
program.command("list").description("List registered atoms").option("--json", "Output structured JSON response").action(async (options) => {
|
|
16
|
+
const { listCommand } = await import("./list-NEBVBGG3.js");
|
|
17
|
+
return listCommand(options);
|
|
18
|
+
});
|
|
19
|
+
program.command("run <atom>").description("Execute an atom (handler or generator)").option("--input <json>", "Input data as JSON string").option("--cache", "Use cached result for idempotent atoms (not yet implemented)").option("-y, --yes", "Skip confirmation for non-idempotent atoms").option("--json", "Output structured JSON response").action(async (target, options) => {
|
|
20
|
+
const { runCommand } = await import("./run-3GI3SBYL.js");
|
|
21
|
+
return runCommand(target, options);
|
|
22
|
+
});
|
|
23
|
+
program.command("test-gen <path>").description("Generate structural tests for an atom").option("--output <path>", "Custom output path for generated tests").option("--json", "Output structured JSON response").action(async (atomPath, options) => {
|
|
24
|
+
const { testGenCommand } = await import("./test-gen-2ZGPOP35.js");
|
|
25
|
+
return testGenCommand(atomPath, options);
|
|
26
|
+
});
|
|
27
|
+
program.command("test <atom>").description("Run tests for an atom").option("--coverage", "Show coverage report").option("--json", "Output structured JSON response").action(async (atomName, options) => {
|
|
28
|
+
const { testCommand } = await import("./test-HP3FG3MO.js");
|
|
29
|
+
return testCommand(atomName, options);
|
|
30
|
+
});
|
|
31
|
+
program.command("status").description("Show current system state").option("--json", "Output structured JSON response").action(async (options) => {
|
|
32
|
+
const { statusCommand } = await import("./status-KQVSAZFR.js");
|
|
33
|
+
return statusCommand(options);
|
|
34
|
+
});
|
|
35
|
+
program.command("history [runId]").description("Show execution history").option("--atom <name>", "Filter to specific atom").option("--limit <n>", "Limit results", "20").option("--json", "Output structured JSON response").action(async (runId, options) => {
|
|
36
|
+
const { historyCommand } = await import("./history-OPD7NLZW.js");
|
|
37
|
+
return historyCommand(runId, options);
|
|
38
|
+
});
|
|
39
|
+
var create = program.command("create").description("Create new atoms or resources");
|
|
40
|
+
create.command("atom <name>").description("Create a new atom with scaffolded files").option("--path <dir>", "Custom output directory").option("--json", "Output structured JSON response").action(async (name, options) => {
|
|
41
|
+
const { createAtomCommand } = await import("./create-atom-AXPDBYQL.js");
|
|
42
|
+
return createAtomCommand(name, options);
|
|
43
|
+
});
|
|
44
|
+
program.command("extract").description("Extract atom from existing skill, BMAD workflow, MCP tool, or code").option("--skill <path>", "Extract from Claude Code skill").option("--bmad <path>", "Extract from BMAD workflow").option("--mcp <path>", "Extract from MCP tool definition").option("--code <path>", "Extract from existing code file").option("--output <dir>", "Output directory for generated atom").option("-y, --yes", "Auto-create without confirmation").option("--json", "Output structured JSON response").action(async (options) => {
|
|
45
|
+
const { extractCommand } = await import("./extract-RPKCTINT.js");
|
|
46
|
+
return extractCommand(options);
|
|
47
|
+
});
|
|
48
|
+
program.command("suggest").description("Scan codebase for functions that could become atoms").option("--path <dir>", "Directory to scan (default: cwd)").option("--limit <n>", "Max candidates to show (default: 20)").option("--scan-limit <n>", "Max files to scan (default: 1000)").option("--json", "Output structured JSON response").action(async (options) => {
|
|
49
|
+
const { suggestCommand } = await import("./suggest-IFFJQFIW.js");
|
|
50
|
+
return suggestCommand(options);
|
|
51
|
+
});
|
|
52
|
+
program.command("graduate <atom>").description("Graduate an atom from handler to generator").option("-y, --yes", "Skip confirmation").option("--json", "Output structured JSON response").action(async (atom, options) => {
|
|
53
|
+
const { graduateCommand } = await import("./graduate-453M7ZRQ.js");
|
|
54
|
+
return graduateCommand({ atom, ...options });
|
|
55
|
+
});
|
|
56
|
+
program.command("revert <atom>").description("Revert a graduated atom back to handler execution").option("--reason <reason>", "Reason for reverting").option("-y, --yes", "Skip confirmation").option("--json", "Output structured JSON response").action(async (atom, options) => {
|
|
57
|
+
const { revertCommand } = await import("./revert-J4CRDE2K.js");
|
|
58
|
+
return revertCommand({ atom, ...options });
|
|
59
|
+
});
|
|
60
|
+
program.command("trust [stack]").description("Manage trust levels for atom stacks").option("--level <level>", "Set trust level (new, proven, trusted)").option("--list", "List all stacks with trust levels").option("--reset", "Reset trust to new level").option("--json", "Output structured JSON response").action(async (stack, options) => {
|
|
61
|
+
const { trustSetCommand, trustListCommand, trustResetCommand } = await import("./trust-4R26DULG.js");
|
|
62
|
+
if (options.list) {
|
|
63
|
+
await trustListCommand({ json: options.json });
|
|
64
|
+
} else if (options.reset) {
|
|
65
|
+
if (!stack) {
|
|
66
|
+
console.error("Error: Stack name required for --reset");
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
await trustResetCommand({ stack, json: options.json });
|
|
70
|
+
} else if (options.level) {
|
|
71
|
+
if (!stack) {
|
|
72
|
+
console.error("Error: Stack name required for --level");
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
await trustSetCommand({ stack, level: options.level, json: options.json });
|
|
76
|
+
} else {
|
|
77
|
+
console.error("Error: Must specify --level, --list, or --reset");
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
var workflow = program.command("workflow").description("Manage and execute workflows");
|
|
82
|
+
workflow.command("run <name>").description("Execute a workflow").option("--dry-run", "Show execution plan without running").option("--force-rebuild <atoms>", "Force rebuild specific atoms (comma-separated)").option("--force-rebuild-all", "Force rebuild all atoms").option("--no-beads", "Disable Beads tracking (enabled by default)").option("--json", "Output structured JSON response").action(async (name, options) => {
|
|
83
|
+
const { workflowRunCommand } = await import("./workflow-5UVLBS7J.js");
|
|
84
|
+
return workflowRunCommand(name, options);
|
|
85
|
+
});
|
|
86
|
+
workflow.command("list").description("List available workflows").option("--json", "Output structured JSON response").action(async (options) => {
|
|
87
|
+
const { workflowListCommand } = await import("./workflow-5UVLBS7J.js");
|
|
88
|
+
return workflowListCommand(options);
|
|
89
|
+
});
|
|
90
|
+
workflow.command("resume <name>").description("Resume a failed or partial workflow").option("--run <runId>", "Specific run ID to resume").option("--from <atom>", "Force restart from specific atom").option("--no-beads", "Disable Beads tracking (enabled by default)").option("--json", "Output structured JSON response").action(async (name, options) => {
|
|
91
|
+
const { workflowResumeCommand } = await import("./workflow-5UVLBS7J.js");
|
|
92
|
+
return workflowResumeCommand(name, options);
|
|
93
|
+
});
|
|
94
|
+
program.command("plan <workflow>").description("Preview workflow execution plan").option("--verbose", "Show detailed atom information").option("--json", "Output structured JSON response").action(async (name, options) => {
|
|
95
|
+
const { planCommand } = await import("./plan-DNVARHWH.js");
|
|
96
|
+
return planCommand(name, options);
|
|
97
|
+
});
|
|
98
|
+
program.command("escalate").description("Create Beads issue for unresolvable problems").option("--message <msg>", "Additional context").option("--run <runId>", "Link to specific run ID").option("--atom <name>", "Atom that failed").option("--reason <reason>", "Why the issue is blocked").option("--retries <n>", "Number of retry attempts", (value) => {
|
|
99
|
+
const parsed = parseInt(value, 10);
|
|
100
|
+
if (isNaN(parsed) || parsed < 0) {
|
|
101
|
+
console.error("Error: --retries must be a non-negative integer");
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
return parsed;
|
|
105
|
+
}).option("--workflow <name>", "Workflow name for context").option("--parent-bead <id>", "Parent bead ID for linking").option("--json", "Output structured JSON response").action(async (options) => {
|
|
106
|
+
const { escalateCommand } = await import("./escalate-BTEJT5NL.js");
|
|
107
|
+
return escalateCommand({
|
|
108
|
+
message: options.message,
|
|
109
|
+
runId: options.run,
|
|
110
|
+
atom: options.atom,
|
|
111
|
+
reason: options.reason,
|
|
112
|
+
retries: options.retries,
|
|
113
|
+
workflowName: options.workflow,
|
|
114
|
+
parentBeadId: options.parentBead,
|
|
115
|
+
json: options.json
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
program.command("scan-generators").description("Detect existing generators (Plop, Hygen, Yeoman, Cookiecutter, custom)").option("--system <system>", "Filter to specific system (plop, hygen, yeoman, cookiecutter, custom)").option("--json", "Output structured JSON response").action(async (options) => {
|
|
119
|
+
const { scanGeneratorsCommand } = await import("./scan-generators-ST4TBEY7.js");
|
|
120
|
+
return scanGeneratorsCommand(options);
|
|
121
|
+
});
|
|
122
|
+
program.command("import-generator").description("Import generators from external systems").option("--plop <name>", "Import Plop generator by name").option("--hygen <name>", "Import Hygen generator (generator/action format)").option("--yeoman <name>", "Import Yeoman generator by name").option("--cookiecutter <path>", "Import Cookiecutter template from path").option("--script <path>", "Import custom script (shell, JS, Python)").option("--output <dir>", "Output directory for generator", "generators").option("--overwrite", "Overwrite existing generator").option("--json", "Output structured JSON response").action(async (options) => {
|
|
123
|
+
const { importGeneratorCommand } = await import("./import-generator-4CKRBMTE.js");
|
|
124
|
+
return importGeneratorCommand(options);
|
|
125
|
+
});
|
|
126
|
+
program.command("validate-generator").description("Validate imported generators by executing with sample params").option("--generator <name>", "Generator to validate").option("--all", "Validate all generators in generators/ directory").option("--json", "Output structured JSON response").action(async (options) => {
|
|
127
|
+
const { validateGeneratorCommand } = await import("./validate-generator-46H2LYYQ.js");
|
|
128
|
+
return validateGeneratorCommand(options);
|
|
129
|
+
});
|
|
130
|
+
var skills = program.command("skills").description("Manage Claude Code skills");
|
|
131
|
+
skills.command("scan").description("Discover available Claude Code skills").option("--json", "Output structured JSON response").action(async (options) => {
|
|
132
|
+
const { skillsScanCommand } = await import("./skills-scan-WACJFRJN.js");
|
|
133
|
+
return skillsScanCommand(options);
|
|
134
|
+
});
|
|
135
|
+
skills.command("suggest <atom>").description("Get skill recommendations for an atom").option("--json", "Output structured JSON response").action(async (atomName, options) => {
|
|
136
|
+
const { skillsSuggestCommand } = await import("./skills-suggest-JFI2NUJI.js");
|
|
137
|
+
return skillsSuggestCommand(atomName, options);
|
|
138
|
+
});
|
|
139
|
+
skills.command("assign <atom>").description("Assign a skill to an atom").requiredOption("--skill <name>", "Skill name to assign").option("--json", "Output structured JSON response").action(async (atomName, options) => {
|
|
140
|
+
const { skillsAssignCommand } = await import("./skills-assign-IHOXX4AI.js");
|
|
141
|
+
return skillsAssignCommand(atomName, options);
|
|
142
|
+
});
|
|
143
|
+
skills.command("list <atom>").description("List skills assigned to an atom").option("--json", "Output structured JSON response").action(async (atomName, options) => {
|
|
144
|
+
const { skillsListAtomCommand } = await import("./skills-assign-IHOXX4AI.js");
|
|
145
|
+
return skillsListAtomCommand(atomName, options);
|
|
146
|
+
});
|
|
147
|
+
skills.command("remove <atom>").description("Remove a skill from an atom").requiredOption("--skill <name>", "Skill name to remove").option("--json", "Output structured JSON response").action(async (atomName, options) => {
|
|
148
|
+
const { skillsRemoveCommand } = await import("./skills-assign-IHOXX4AI.js");
|
|
149
|
+
return skillsRemoveCommand(atomName, options);
|
|
150
|
+
});
|
|
151
|
+
program.parse();
|
|
152
|
+
//# sourceMappingURL=cli.js.map
|