{"_id":"@atarashi/core","name":"@atarashi/core","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@atarashi/core","version":"1.0.0","description":"The Atarashi generation engine: resolve, render, merge, plan, write.","type":"module","license":"MIT","author":"Gautam Suthar <iamgautamsuthar@gmail.com> (https://www.github.com/callmegautam)","repository":{"type":"git","url":"git+https://github.com/callmegautam/atarashi.git","directory":"packages/core"},"homepage":"https://github.com/callmegautam/atarashi/tree/main/packages/core#readme","bugs":{"url":"https://github.com/callmegautam/atarashi/issues"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20.11"},"dependencies":{"handlebars":"^4.7.8","semver":"^7.7.2","yaml":"^2.8.1","@atarashi/schema":"1.0.0"},"devDependencies":{"@types/semver":"^7.7.1"},"publishConfig":{"access":"public"},"scripts":{"build":"tsup","typecheck":"tsc --noEmit -p tsconfig.json","test":"vitest run --coverage","test:coverage":"vitest run --coverage","clean":"rm -rf dist .turbo"},"_nodeVersion":"26.2.0","_id":"@atarashi/core@1.0.0","dist":{"integrity":"sha512-kF2aAelFr56pYSJgowJX0PI8UrNLf/XuXisxqqo48qAhfwqJSe5RwZtfWqPUmzwORmRYNEQlQ3q8JLanjAOWiw==","shasum":"69c1701f4365e06fdb89c8fbc7394e6f12d25e36","tarball":"https://registry.npmjs.org/@atarashi/core/-/core-1.0.0.tgz","fileCount":6,"unpackedSize":435811,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBWhCC8IljAfFr6b0L1k3hB1QUS5Mbz7p57+nms3kyfHAiB5cvklvewaQRokZz7hVSLTwE6EZBsIVfRAch94rpmJIQ=="}]},"_npmUser":{"name":"iamgautamsuthar","email":"iamgautamsuthar@gmail.com"},"directories":{},"maintainers":[{"name":"iamgautamsuthar","email":"iamgautamsuthar@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core_1.0.0_1789054550593_0.13777651426383075"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-10T15:35:50.223Z","1.0.0":"2026-09-10T15:35:50.743Z","modified":"2026-09-10T15:35:51.014Z"},"maintainers":[{"name":"iamgautamsuthar","email":"iamgautamsuthar@gmail.com"}],"description":"The Atarashi generation engine: resolve, render, merge, plan, write.","homepage":"https://github.com/callmegautam/atarashi/tree/main/packages/core#readme","repository":{"type":"git","url":"git+https://github.com/callmegautam/atarashi.git","directory":"packages/core"},"author":"Gautam Suthar <iamgautamsuthar@gmail.com> (https://www.github.com/callmegautam)","bugs":{"url":"https://github.com/callmegautam/atarashi/issues"},"license":"MIT","readme":"# @atarashi/core\n\nThe Atarashi generation engine. Takes a `ProjectSpec`, returns a\n`GenerationPlan`. Pure: it never calls `process.exit`, never writes to stdout,\nnever prompts, and never touches disk until you explicitly commit a plan.\n\n```ts\nimport { generate, commit, runActions } from '@atarashi/core';\n\nconst plan = await generate(spec, { source: registry, atarashiVersion: '1.0.0' });\nif (!plan.ok) {\n    for (const d of plan.error.diagnostics) console.error(d.message);\n    process.exit(1);\n}\n\n// Everything above is side-effect free; this is where the disk is touched.\nconst written = commit(plan.value, '/path/to/my-api');\nawait runActions(plan.value, spec, { targetDir: '/path/to/my-api' });\n```\n\n## The pipeline\n\n| Stage | What it does |\n|---|---|\n| `resolve` | Selected ids → an ordered, validated blueprint graph. Expands `requires`, auto-adds unambiguous providers, detects conflicts and cycles, checks `engines`. |\n| `buildContext` | One frozen object read by every template and every `when` expression. |\n| `render` | Per-file `when`, path templating, Handlebars with a curated helper set → `FileFragment[]`. |\n| `collect` | Dependencies, scripts, env vars, gitignore lines and next steps → more fragments, so declarative content and templated content share one merge path. |\n| `merge` | Groups fragments by path and reduces them with the declared strategy; injects slot contributions. |\n| `assemblePlan` | Files + post-actions + warnings + dependency summary + `atarashi.json`. |\n| `HookRunner` | Runs `beforeRender`, `afterRender` and `afterPlan` in a sandboxed worker between the stages they are named for. |\n| `validatePlan` | Size caps, case collisions, path escapes, JSON/YAML syntax, undeclared env keys. |\n| `commit` | Stage to a temp dir, fsync, atomic rename, full rollback on any failure. |\n\n## Invariants worth preserving\n\n- **The plan is a virtual filesystem.** `--dry-run`, the web preview, the zip\n  download and snapshot tests all fall out of this for free. If you add a stage,\n  it operates on the VFS, not on disk.\n- **Determinism.** Identical inputs produce byte-identical output. Everything\n  iterated is sorted; graph order is total (`after` → `priority` → id).\n- **No silent overwrites.** Two blueprints writing one path is a conflict unless\n  a strategy says otherwise.\n- **Every path is checked twice**: once when it enters the VFS, once against\n  the resolved target directory before the writer moves anything.\n- **Hook output is untrusted input.** Anything a hook returns re-enters through\n  the same normalization and the same `validatePlan` gate as rendered output.\n\n## Hooks\n\nA blueprint may declare `hooks: { module, exports, capabilities, timeoutMs }`.\nEach hook runs in its own `node:worker_thread` with:\n\n- an **empty environment** (`env: {}`), no `argv`, no `execArgv`, and no\n  `fetch`, `WebSocket` or `XMLHttpRequest`;\n- a **module loader** that allows only pure builtins (`path`, `url`, `util`,\n  `buffer`, `assert`, `events`, `querystring`, `string_decoder`) and refuses any\n  import resolving outside the blueprint's own directory;\n- a **hard timeout** (the manifest's `timeoutMs`, capped at 30 s) after which\n  the worker is terminated;\n- only what its capabilities allow: `read-files` to see the file list,\n  `write-files` for its changes to be kept, `read-context` to receive the render\n  context.\n\nA hook never touches the filesystem. It mutates a structured clone of its\nsubject and the runner copies back the permitted fields. Blueprints from\nuntrusted sources need explicit consent (`hooks.consent`), and `--no-hooks`\n(`hooks.enabled: false`) skips every hook with a warning rather than failing.\n\n## The `when` expression language\n\nA small non-Turing-complete language, parsed to an AST and interpreted, never\n`eval`'d. Bindings: `answers.*`, `project.*`, `options.*`, `pm.*`, `has(id)`,\n`provides(capability)`. Operators: `&& || ! === !== < <= > >= + -` and `in`.\nNo member calls, no loops, no property access on call results.\n","readmeFilename":"","_rev":"1-9e3834e6d07f9533d1dcac3323a4080b"}