@aid-framework/generator-sdk

中文文档
0.1.98发布于 2026/11/03Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 1.2万

The AID Framework generator plugin interface: the manifest contract, the drift/ownership algorithm, and the determinism helpers every target generator emits through.

原始使用文档
文档目录10 节
  1. Install
  2. The three jobs
  3. The manifest
  4. generated/ and business/
  5. The drift algorithm
  6. Determinism
  7. The manifest on disk
  8. The generator interface
  9. API
  10. License

@aid-framework/generator-sdk

The plugin contract for AID Framework generators. It defines what a generator is, and supplies the three things every generator needs in order to be safe to re-run: a manifest, an ownership and drift algorithm, and a determinism contract.

If you are writing a target — a new language, a new hosting platform — this is the package you implement. If you are only using AID, you do not call it directly: aid gen does.

spec ← ir ← generator-sdk ← generator-<target> ← cli

Install

npm install @aid-framework/generator-sdk

Requires Node.js 24 or newer.

The three jobs

  1. Say what you are. A manifest declares the target id, the IR range you accept, the capabilities you can honour, and the runtime you emit against.
  2. Never destroy a human's edit. Files are split into a generator-owned tier and a developer-owned tier, and regeneration refuses to overwrite a generated file whose bytes have changed.
  3. Emit the same bytes twice. Given the same IR, a generator must produce byte-identical output — no timestamps, no host names, no absolute paths, no randomness.

The manifest

import type { GeneratorManifestInput } from '@aid-framework/generator-sdk';

const input: GeneratorManifestInput = {
  name: 'my-target',
  target: 'my-target',
  version: '0.1.0',
  irRange: '^0.1.0',
  capabilities: ['http-trigger', 'json-schema', 'otel'],
  emitsAgainst: {
    structuredOutput: 'zod',
    tracing: 'otel-genai',
  },
  output: {
    root: 'app',
    generatedDir: 'generated',
    businessDir: 'business',
  },
};

const parsed = parseManifest(input);
if (!parsed.ok) throw new Error(JSON.stringify(parsed.diagnostics, null, 2));

checkIRSupport(parsed.manifest, IR_VERSION);  // [] when irRange covers this IR
validateGeneratorSet([parsed.manifest]);      // [] when the set is coherent

emitsAgainst is what makes two targets comparable. A target emitting Pydantic models and OTel spans is not interchangeable with one emitting Zod and a different tracer, and the declaration says so in data rather than in prose.

KeyVocabulary
runtimeThe runtime the output is paired with, e.g. py-fastapi
orchestrationORCHESTRATIONS
tracingBackendTRACING_BACKENDS, e.g. otel-genai
structuredOutputSTRUCTURED_OUTPUTS, e.g. zod, pydantic

Validation returns diagnostics, never thrown exceptions, in the same compiler-style shape as @aid-framework/spec and @aid-framework/ir. Codes are namespaced generator/*. validateGeneratorSet additionally rejects two generators claiming the same target.

A manifest is data, which is why capabilities travel into the IR gates as an argument:

import { targetCapabilityDeclarations } from '@aid-framework/generator-sdk';
import { runGates } from '@aid-framework/ir';

runGates(ir, { targetCapabilities: targetCapabilityDeclarations(manifests) });

generated/ and business/

The two-tier split is the reason regeneration is safe.

TierOwnerOn regeneration
generated/the generatoroverwritten — never hand-edit
business/youcreated once if missing, then never touched

business/ is the seam: it is what generated code calls into. That is where your prompts, tool handlers and domain logic live, and it is why regenerating does not cost you your work.

Ownership is decided by where a path lives, not by what a generator claims. Every planned path is normalized, so a generator cannot escape its own root, cannot claim a business/ path as generated, and cannot write the manifest file itself.

import {
  isBusinessPath, isGeneratedPath, isReservedPath, ownerForPath, validatePlan,
} from '@aid-framework/generator-sdk';

The drift algorithm

This is the whole safety story, in five steps:

  1. Plan. plan(ir) is pure. It writes nothing.
  2. Check generated files. If a planned generated/ file exists and its hash is not the one recorded in the manifest, a human edited it. Do not overwrite. Write the new content beside it as <path>.aid-rej and fail with guidance.
  3. Create business files. Only if missing. Never overwrite.
  4. Write atomically, then update the manifest.
  5. Report created / updated / unchanged / kept / conflicts.

Step 2 is the point. A generator that overwrites unconditionally destroys the one signal it has that a human disagreed with it, and the loss is silent. Refusing, keeping the rejected bytes, and naming the escape — --force to discard the edit — turns silent data loss into a decision you make explicitly.

import { hasDrift, planRegeneration, regenerate } from '@aid-framework/generator-sdk';

// Pure: computes what would happen and writes nothing.
const preview = planRegeneration(plan, { sink, manifest });
if (hasDrift(preview)) {
  // preview.actions carries { kind: 'drift', path, recordedSha256, actualSha256 }
}

const { report, manifest: next } = regenerate(plan, { sink, manifest, provenance });

RegenerationAction is create | update | unchanged | keep-business | drift, so --dry-run renders from the same code path that writes.

Two limits are deliberate:

  • A file under generated/ that exists but has no record in the manifest is treated as drift rather than adopted, because it cannot be proven unmodified.
  • Stale generated files — recorded but no longer planned — are reported but never deleted unless pruning is requested explicitly. Deletion is the one operation with no recovery.

Determinism

The contract is narrow and absolute: no timestamps, no host names, no absolute paths, no randomness in generated code. One timestamp turns every regeneration into a diff, and golden-file tests compare bytes.

import { checkDeterminism } from '@aid-framework/generator-sdk';

const violations = checkDeterminism(files); // { path, pattern, line, excerpt }[]
ExportPurpose
normalizeNewlines, ensureTrailingNewline, normalizeTextLine-ending and trailing-newline normalization
sha256Hex, stableIdContent hashes and stable identities
compareIds, sortById, sortByPath, stableSortByOrder by a stable id, not by walk order
generatedBannerThe do-not-edit header and its marker
DETERMINISM_PATTERNS, scanForNonDeterminismThe rule set and a per-file checker
checkDeterminismRun the whole rule set over a file set

scanForNonDeterminism is what lets a generator's own tests fail the build when it emits a timestamp. That is what makes the contract testable instead of aspirational.

The contract applies to generated code, never to model output. Completions are expected to vary; eval gating accounts for that by sampling rather than by comparing bytes.

The manifest on disk

aid.manifest.json records provenance — generator name and version, IR version, spec version — plus one entry per file: path, owner, sha256, generator, generatorVersion. That record is what makes step 2 above possible.

import { manifestFor, parseAidManifestJson, serializeAidManifest } from '@aid-framework/generator-sdk';

const written = manifestFor(files, provenance);
const text = serializeAidManifest(written); // canonical: sorted keys, LF, one trailing newline

The generator interface

import type { Generator } from '@aid-framework/generator-sdk';

export const myGenerator: Generator = {
  name: manifest.name,
  target: manifest.target,
  version: manifest.version,
  irRange: manifest.irRange,
  plan: (ir) => planMyTarget(ir),
  emit: (plan) => plan.files,
};

Every identity field is read off the manifest, so a manifest a loader validated and the generator it then ran cannot disagree about which target, version or IR range they describe.

API

ExportPurpose
parseManifest, parseManifestJson, validateManifest, validateGeneratorSetManifest handling
checkIRSupport, supportsIRIR range compatibility
managedRoots, targetCapabilityDeclarationsManifest → IR gates
validatePlan, isRecordPlan validation
planRegeneration, regenerate, checkDrift, hasDriftThe drift algorithm
staleGeneratedFiles, generatedFilesInventory of a previous run
createNodeSink, createMemorySinkOn-disk and in-memory regeneration sinks
ownerForPath, isGeneratedPath, isBusinessPath, isReservedPath, escapesRootOwnership predicates
rejectionPathWhere rejected bytes are parked
manifestFor, parseAidManifest, serializeAidManifestThe on-disk manifest
checkDeterminism, DETERMINISM_PATTERNS, scanForNonDeterminismDeterminism
parseRange, satisfies, compareVersionsThe shared semver vocabulary

License

Apache-2.0. Code generated by AID Framework is not subject to this license.

版本与发布记录

@aid-framework/generator-sdk 共发布 52 个版本,首次发布于 2026/10/31;过去 12 个月发布了 52 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.1.98latest2026/11/032 天前
0.1.972026/11/032 天前
0.1.962026/11/033 天前
0.1.952026/11/033 天前
0.1.942026/11/033 天前
0.1.932026/11/033 天前

关于 @aid-framework/generator-sdk 的常见问题

@aid-framework/generator-sdk 是什么?

The AID Framework generator plugin interface: the manifest contract, the drift/ownership algorithm, and the determinism helpers every target generator emits through.

如何安装 @aid-framework/generator-sdk?

在项目目录运行 npm install @aid-framework/generator-sdk,或使用 pnpm add / yarn add / bun add。

@aid-framework/generator-sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@aid-framework/generator-sdk 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@aid-framework/generator-sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@aid-framework/generator-sdk 可以商用吗?

@aid-framework/generator-sdk 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@aid-framework/generator-sdk 的下载量有多少?

根据 npm 官方下载统计,@aid-framework/generator-sdk 在 2026/10/06 – 2026/11/04 这 30 天内被下载 11,718 次,日均约 391 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@aid-framework/generator-sdk 还在维护吗?

最新版本 0.1.98 发布于 2026/11/03(2 天前);至今共发布 52 个版本,其中过去 12 个月发布了 52 个;首次发布于 2026/10/31。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。