Package Exports
- @karmaniverous/stan-core
Readme
Engine for STAN — programmatic archiving/diffing, patch application, config loading, file selection, and imports staging. No CLI/TTY concerns.
@karmaniverous/stan-core (engine)
This package exposes the STAN engine as a library:
- File selection (gitignore + includes/excludes + reserved workspace rules)
- Archiving: full archive.tar and diff archive.diff.tar (binary screening)
- Patch engine: worktree‑first git apply cascade with jsdiff fallback
- File Ops: safe mv/rm/rmdir/mkdirp block as “pre‑ops”
- Config loading/validation (top‑level
stan-corein stan.config.yml|json) - Imports staging under
/imports/ - Response‑format validator (optional)
For the CLI and TTY runner, see @karmaniverous/stan-cli.
Install
pnpm add @karmaniverous/stan-core
# or npm i @karmaniverous/stan-coreNode: >= 20
Quick examples
Create a full archive (binary‑safe) and a diff archive:
import { createArchive } from '@karmaniverous/stan-core/stan';
import { createArchiveDiff } from '@karmaniverous/stan-core/stan/diff';
const cwd = process.cwd();
const stanPath = '.stan';
// Full archive (excludes <stanPath>/diff and binaries; include outputs with { includeOutputDir: true })
const fullTar = await createArchive(cwd, stanPath, { includeOutputDir: false });
// Diff archive (changes vs snapshot under <stanPath>/diff)
const { diffPath } = await createArchiveDiff({
cwd,
stanPath,
baseName: 'archive',
includeOutputDirInDiff: false,
updateSnapshot: 'createIfMissing',
});Apply a unified diff (with safe fallback) and/or run File Ops:
import {
applyPatchPipeline,
detectAndCleanPatch,
executeFileOps,
parseFileOpsBlock,
} from '@karmaniverous/stan-core/stan/patch';
const cwd = process.cwd();
// File Ops (pre‑ops) example
const plan = parseFileOpsBlock(
[
'### File Ops',
'mkdirp src/new/dir',
'mv src/old.txt src/new/dir/new.txt',
].join('\n'),
);
if (plan.errors.length) throw new Error(plan.errors.join('\n'));
await executeFileOps(cwd, plan.ops, false);
// Unified diff example (from a string)
const cleaned = detectAndCleanPatch(`
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,1 +1,1 @@
-old
+new
`);
const out = await applyPatchPipeline({
cwd,
patchAbs: '/dev/null', // absolute path to a saved .patch file (not required for js fallback)
cleaned,
check: false, // true => sandbox write
});
if (!out.ok) {
// Inspect out.result.captures (git attempts) and out.js?.failed (jsdiff reasons)
}Load and validate repo config (namespaced stan-core in stan.config.yml|json):
YAML example:
stan-core:
stanPath: .stan
includes: []
excludes:
- CHANGELOG.md
imports:
cli-docs:
- ../stan-cli/.stan/system/stan.requirements.md
- ../stan-cli/.stan/system/stan.todo.mdTypeScript:
import { loadConfig } from '@karmaniverous/stan-core/stan/config';
const cfg = await loadConfig(process.cwd());
// cfg has the minimal engine shape:
// {
// stanPath: string; includes?: string[]; excludes?: string[];
// imports?: Record<string, string[]>
// }Stage external imports under
import { prepareImports } from '@karmaniverous/stan-core/stan';
await prepareImports({
cwd: process.cwd(),
stanPath: '.stan',
map: {
'@scope/docs': ['external/docs/**/*.md'],
},
});Validate assistant responses (optional utility):
import { validateResponseMessage } from '@karmaniverous/stan-core/stan';
const res = validateResponseMessage(replyBody);
if (!res.ok) console.error(res.errors.join('\n'));API surface
Top‑level (via import '@karmaniverous/stan-core/stan'):
- Archiving/diff/snapshot:
createArchive,createArchiveDiff,writeArchiveSnapshot - Selection/FS:
listFiles,filterFiles - Patch engine:
applyPatchPipeline,detectAndCleanPatch,executeFileOps,parseFileOpsBlock - Imports:
prepareImports - Config:
loadConfig,loadConfigSync,resolveStanPath,resolveStanPathSync - Validation:
validateResponseMessage
See CHANGELOG for behavior changes. Typedoc site is generated from source.
Selection precedence and anchors
Core file selection applies in this order:
- Reserved denials always win and cannot be overridden:
.git/**,<stanPath>/diff/**,<stanPath>/patch/**,- archive outputs under
<stanPath>/output/…, - binary screening during archive classification.
includesoverride.gitignore(but notexcludes).excludesoverrideincludes.anchors(optional) re‑include paths after excludes and.gitignore, subject to reserved denials and binary screening.
APIs that accept anchors:
filterFiles(files, { …, anchors?: string[] })createArchive(cwd, stanPath, { …, anchors?: string[] })createArchiveDiff({ …, anchors?: string[] })writeArchiveSnapshot({ …, anchors?: string[] })
Environment variables
See ENVIRONMENT.md for a complete list of environment variable switches observed by the engine, tests, and release scripts.
Migration (legacy configs)
This engine expects a top‑level, namespaced stan-core block in stan.config.yml|json. If your repository still uses legacy, flat keys at the root, migrate with the CLI:
stan init # offers to refactor legacy → namespaced; supports --dry-run and backupsLicense
BSD‑3‑Clause