Engine for STAN — programmatic archiving/diffing/snapshotting, patch application, config loading, selection, and imports staging. No CLI/TTY concerns.
npm install @karmaniverous/stan-core> Engine for STAN — programmatic archiving/diffing, patch application, config loading, file selection, and imports staging. No CLI/TTY concerns.
 !Node Current   
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/cp/rm/rmdir/mkdirp block as “pre‑ops”
- Config loading/validation (top‑level stan-core in stan.config.yml|json)
- Imports staging under
For the CLI and TTY runner, see @karmaniverous/stan-cli.
``bash`
pnpm add @karmaniverous/stan-coreor npm i @karmaniverous/stan-core
Node: >= 20
This package is ESM-only (no CommonJS require() entrypoint).
Create a full archive (binary‑safe) and a diff archive:
`ts
import { createArchive, createArchiveDiff } from '@karmaniverous/stan-core';
const cwd = process.cwd();
const stanPath = '.stan';
// Full archive (excludes
const fullTar = await createArchive(cwd, stanPath, { includeOutputDir: false });
// Diff archive (changes vs snapshot under
const { diffPath } = await createArchiveDiff({
cwd,
stanPath,
baseName: 'archive',
includeOutputDirInDiff: false,
updateSnapshot: 'createIfMissing',
});
`
Create a full archive from an explicit allowlist (context-mode building block):
`ts
${stanPath}/system/stan.system.md
import { createArchiveFromFiles } from '@karmaniverous/stan-core';
const cwd = process.cwd();
const stanPath = '.stan';
const tarPath = await createArchiveFromFiles(
cwd,
stanPath,
[
// repo-relative POSIX paths
'README.md',
,
`
],
{ includeOutputDir: false },
);
Apply a unified diff (with safe fallback) and/or run File Ops:
`ts
import {
applyPatchPipeline,
detectAndCleanPatch,
executeFileOps,
parseFileOpsBlock,
} from '@karmaniverous/stan-core';
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:
`yaml`
stan-core:
stanPath: .stan
includes: []
excludes:
- CHANGELOG.md
imports:
cli-docs:
- ../stan-cli/.stan/system/stan.requirements.md
- ../stan-cli/.stan/system/stan.todo.md
TypeScript:
`ts
import { loadConfig } from '@karmaniverous/stan-core';
const cfg = await loadConfig(process.cwd());
// cfg has the minimal engine shape:
// {
// stanPath: string; includes?: string[]; excludes?: string[];
// imports?: Record
// }
`
Stage external imports under
`ts`
import { prepareImports } from '@karmaniverous/stan-core';
await prepareImports({
cwd: process.cwd(),
stanPath: '.stan',
map: {
'@scope/docs': ['external/docs/*/.md'],
},
});
Top‑level (via import '@karmaniverous/stan-core'):
- Archiving/diff/snapshot (denylist selection): createArchive, createArchiveDiff, writeArchiveSnapshot
createArchiveFromFiles
- Archiving/diff/snapshot (explicit allowlist): , createArchiveDiffFromFiles, writeArchiveSnapshotFromFiles
listFiles
- Selection/FS: , filterFilesapplyPatchPipeline
- Patch engine: , detectAndCleanPatch, executeFileOps, parseFileOpsBlockprepareImports
- Imports: loadConfig
- Config: , loadConfigSync, resolveStanPath, resolveStanPathSynccreateContextArchiveWithDependencyContext
- Context mode orchestration (Base + closure allowlist): , createContextArchiveDiffWithDependencyContext
See CHANGELOG for behavior changes. Typedoc site is generated from source.
Core file selection applies in this order:
- Reserved denials always win and cannot be overridden:
- .git/, , ,
- archive outputs under ,includes
- binary screening during archive classification.
- are additive and can re-include paths ignored by .gitignore.excludes
- are hard denials and override includes.
When dependency graph mode is enabled, the engine can create a small “meta archive” (via createMetaArchive) intended as a thread opener. In stan run --context --meta, the host writes this archive as archive.tar (and does not write a diff archive).
- Includes (excluding )
- Includes (required)
- Includes (v2) when present (the host writes { "v": 2, "i": [] } before archiving for a clean-slate selection)
- Includes repo-root (top-level) base files selected by current selection config
- Optionally includes when includeOutputDir: true (combine mode); archive files are still excluded by tar filter
- Excludes staged payloads under by omission
When you call buildDependencyMeta(...), @karmaniverous/stan-core delegates dependency graph generation to its peer dependency @karmaniverous/stan-context.
TypeScript must be provided by the host environment (typically stan-cli) via either typescript (preferred) or typescriptPath. stan-core does not attempt to resolve or import TypeScript itself; it passes these values through to stan-context.
If neither typescript nor typescriptPath is provided, buildDependencyMeta will throw (the error originates from stan-context).
Minimal example:
`ts`
import ts from 'typescript';
import { buildDependencyMeta } from '@karmaniverous/stan-core';
await buildDependencyMeta({
cwd: process.cwd(),
stanPath: '.stan',
typescript: ts,
});
) should use the engine-owned orchestration helpers:
`ts
import {
createContextArchiveWithDependencyContext,
createContextArchiveDiffWithDependencyContext,
} from '@karmaniverous/stan-core';
const cwd = process.cwd();
const stanPath = '.stan';
const full = await createContextArchiveWithDependencyContext({
cwd,
stanPath,
dependency: { meta, map, state, clean: true },
archive: {
onArchiveWarnings: (text) => console.log(text),
onSelectionReport: (report) => console.log(report),
},
});
const diff = await createContextArchiveDiffWithDependencyContext({
cwd,
stanPath,
dependency: { meta, map, state, clean: false },
diff: {
baseName: 'archive',
snapshotFileName: '.archive.snapshot.context.json',
onArchiveWarnings: (text) => console.log(text),
onSelectionReport: (report) => console.log(report),
},
});
`
Environment variables
See Env Vars 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:`bash
stan init # offers to refactor legacy → namespaced; supports --dry-run and backups
``BSD‑3‑Clause
---
Built for you with ❤️ on Bali! Find more great tools & templates on my GitHub Profile.