@aid-framework/generator-sdk 0.1.57 → 0.1.59

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/dist/eject.js ADDED
@@ -0,0 +1,169 @@
1
+ /**
2
+ * `aid eject` (§10): taking ownership of a generated file.
3
+ *
4
+ * Ejection is the developer's answer to the drift rule. When a generated file needs
5
+ * hand-editing, the choice is to keep discarding the edits with `--force`, or to own the
6
+ * file. Owning it means two things, and both are required:
7
+ *
8
+ * 1. **The bytes move to the business tier.** Ownership is decided by *where a path
9
+ * lives* (`ownership.ts`), not by a flag, so flipping ownership is a move from
10
+ * `<generatedDir>/x` to `<businessDir>/x`. A manifest flag alone would contradict
11
+ * the location rule the planner enforces.
12
+ * 2. **The generated path is excluded forever.** The manifest records it in `ejected`,
13
+ * and `planRegeneration` drops it from every plan. Without this the next `gen` would
14
+ * simply recreate the generated file and the edit would be lost again.
15
+ *
16
+ * The write order is deliberate: destination first, source second. An interrupted eject
17
+ * leaves two copies, never zero.
18
+ *
19
+ * Two refusals are not negotiable. Ejecting onto a business file with different bytes
20
+ * would destroy developer-owned content — the one thing the ownership model protects —
21
+ * so it fails and names the file to move aside. Ejecting a path the manifest never
22
+ * recorded has nothing to transfer and is refused rather than manufacturing a business
23
+ * file from an accident.
24
+ */
25
+ import { manifestRecordFor } from './aid-manifest.js';
26
+ import { sha256Hex, sortByPath } from './determinism.js';
27
+ import { GENERATOR_DIAGNOSTIC_CODES, generatorError, } from './diagnostics.js';
28
+ import { DEFAULT_BUSINESS_DIR, DEFAULT_GENERATED_DIR, normalizeRelativePath, ownerForPath, } from './ownership.js';
29
+ function stripTrailingSlashes(value) {
30
+ let end = value.length;
31
+ while (end > 0 && value[end - 1] === '/')
32
+ end--;
33
+ return value.slice(0, end);
34
+ }
35
+ /**
36
+ * The business-tier home of a generated path: `<generatedDir>/a/b.py` becomes
37
+ * `<businessDir>/a/b.py`. Returns `undefined` for anything that is not a file directly
38
+ * beneath the generated root, so a caller cannot "eject" a directory or a foreign path.
39
+ */
40
+ export function businessPathFor(path, options = {}) {
41
+ const normalized = normalizeRelativePath(path);
42
+ if (normalized === undefined)
43
+ return undefined;
44
+ const generatedDir = stripTrailingSlashes(options.generatedDir ?? DEFAULT_GENERATED_DIR);
45
+ const businessDir = stripTrailingSlashes(options.businessDir ?? DEFAULT_BUSINESS_DIR);
46
+ if (!normalized.startsWith(`${generatedDir}/`))
47
+ return undefined;
48
+ const rest = normalized.slice(generatedDir.length + 1);
49
+ if (rest === '')
50
+ return undefined;
51
+ return `${businessDir}/${rest}`;
52
+ }
53
+ function refuse(diagnostic) {
54
+ return { ok: false, diagnostics: [diagnostic] };
55
+ }
56
+ /**
57
+ * Moves one generated file to the business tier and records a permanent exclusion.
58
+ *
59
+ * Idempotent by design: ejecting a path that is already developer-owned succeeds with
60
+ * `status: 'already-owned'`, so a script can call it without first asking whether the
61
+ * file was ejected.
62
+ */
63
+ export function eject(request) {
64
+ const dryRun = request.dryRun ?? false;
65
+ const path = normalizeRelativePath(request.path);
66
+ if (path === undefined) {
67
+ return refuse(generatorError({
68
+ code: GENERATOR_DIAGNOSTIC_CODES.ejectInvalidPath,
69
+ message: `"${request.path}" is not a repo-relative path, so it cannot name a generated file.`,
70
+ path: request.path,
71
+ hint: 'Pass the path `aid gen` prints, for example `app/generated/prompts/triage.py`.',
72
+ }));
73
+ }
74
+ // Scaffold content is authored once and owned by the developer from then on, so there
75
+ // is nothing to transfer and nothing to look up. Checked before the manifest guard: the
76
+ // answer does not depend on the tree ever having been generated.
77
+ if (ownerForPath(path, request) === 'scaffold') {
78
+ return { ok: true, status: 'already-owned', from: path, dryRun, diagnostics: [] };
79
+ }
80
+ const manifest = request.manifest;
81
+ if (manifest === undefined) {
82
+ return refuse(generatorError({
83
+ code: GENERATOR_DIAGNOSTIC_CODES.ejectNotGenerated,
84
+ message: 'There is no manifest, so this tree has never been generated and has nothing to eject.',
85
+ hint: 'Run `aid gen` first; ejection transfers a file the generator wrote.',
86
+ }));
87
+ }
88
+ const record = manifestRecordFor(manifest, path);
89
+ if (record === undefined) {
90
+ // A business path the generator never planned is already owned by the developer;
91
+ // asking to eject it is a no-op, not a mistake. The same is true of a generated path
92
+ // already in the ledger: the file has moved, so there is no record left, and the
93
+ // ledger is the only proof the transfer happened. Without this lookup a second eject
94
+ // would report "not generated" for a file this command ejected itself. Scaffold paths
95
+ // are handled above, before the manifest guard.
96
+ if (ownerForPath(path, request) === 'business' || manifest.ejected.includes(path)) {
97
+ return { ok: true, status: 'already-owned', from: path, dryRun, diagnostics: [] };
98
+ }
99
+ return refuse(generatorError({
100
+ code: GENERATOR_DIAGNOSTIC_CODES.ejectNotGenerated,
101
+ message: `"${path}" is not recorded in the manifest, so there is no generated artifact to take ownership of.`,
102
+ path,
103
+ hint: 'Eject a path the manifest lists as generated; `aid doctor` prints them.',
104
+ }));
105
+ }
106
+ if (record.owner === 'business') {
107
+ return { ok: true, status: 'already-owned', from: record.path, dryRun, diagnostics: [] };
108
+ }
109
+ const to = businessPathFor(record.path, request);
110
+ if (to === undefined) {
111
+ return refuse(generatorError({
112
+ code: GENERATOR_DIAGNOSTIC_CODES.ejectInvalidPath,
113
+ message: `"${record.path}" has no business-tier counterpart under the configured roots.`,
114
+ path: record.path,
115
+ }));
116
+ }
117
+ const content = request.sink.read(record.path);
118
+ if (content === undefined) {
119
+ return refuse(generatorError({
120
+ code: GENERATOR_DIAGNOSTIC_CODES.ejectMissingFile,
121
+ message: `"${record.path}" is recorded as generated but is missing from the tree.`,
122
+ path: record.path,
123
+ hint: 'Run `aid gen` to restore it, then eject.',
124
+ }));
125
+ }
126
+ const existing = request.sink.read(to);
127
+ if (existing !== undefined && existing !== content) {
128
+ return refuse(generatorError({
129
+ code: GENERATOR_DIAGNOSTIC_CODES.ejectDestinationExists,
130
+ message: `"${to}" already exists and differs from "${record.path}"; ejecting would overwrite developer-owned content.`,
131
+ path: to,
132
+ hint: 'Move or delete that file yourself, then run eject again.',
133
+ }));
134
+ }
135
+ const written = existing === undefined;
136
+ if (!dryRun) {
137
+ if (written)
138
+ request.sink.write(to, content);
139
+ request.sink.remove(record.path);
140
+ }
141
+ const businessRecord = {
142
+ path: to,
143
+ owner: 'business',
144
+ sha256: sha256Hex(content),
145
+ generator: record.generator,
146
+ generatorVersion: record.generatorVersion,
147
+ };
148
+ return {
149
+ ok: true,
150
+ status: 'ejected',
151
+ from: record.path,
152
+ to,
153
+ written,
154
+ dryRun,
155
+ manifest: {
156
+ manifestVersion: manifest.manifestVersion,
157
+ generatedBy: manifest.generatedBy,
158
+ files: sortByPath([
159
+ ...manifest.files.filter((file) => file.path !== record.path && file.path !== to),
160
+ businessRecord,
161
+ ]),
162
+ // Sorted and de-duplicated: two routes to the same exclusion must not produce two
163
+ // entries, and a stable order is what makes the manifest byte-comparable.
164
+ ejected: [...new Set([...manifest.ejected, record.path])].sort(),
165
+ },
166
+ diagnostics: [],
167
+ };
168
+ }
169
+ //# sourceMappingURL=eject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eject.js","sourceRoot":"","sources":["../src/eject.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAA0C,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EACL,0BAA0B,EAE1B,cAAc,GACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAOxB,SAAS,oBAAoB,CAAC,KAAa;IACzC,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,OAAO,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG;QAAE,GAAG,EAAE,CAAC;IAChD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,OAAO,GAAuB,EAAE;IAEhC,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE/C,MAAM,YAAY,GAAG,oBAAoB,CAAC,OAAO,CAAC,YAAY,IAAI,qBAAqB,CAAC,CAAC;IACzF,MAAM,WAAW,GAAG,oBAAoB,CAAC,OAAO,CAAC,WAAW,IAAI,oBAAoB,CAAC,CAAC;IAEtF,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,YAAY,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACjE,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvD,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAElC,OAAO,GAAG,WAAW,IAAI,IAAI,EAAE,CAAC;AAClC,CAAC;AA4BD,SAAS,MAAM,CAAC,UAA+B;IAC7C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;AAClD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,OAAqB;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IAEvC,MAAM,IAAI,GAAG,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,MAAM,CACX,cAAc,CAAC;YACb,IAAI,EAAE,0BAA0B,CAAC,gBAAgB;YACjD,OAAO,EAAE,IAAI,OAAO,CAAC,IAAI,oEAAoE;YAC7F,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,gFAAgF;SACvF,CAAC,CACH,CAAC;IACJ,CAAC;IAED,sFAAsF;IACtF,wFAAwF;IACxF,iEAAiE;IACjE,IAAI,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,UAAU,EAAE,CAAC;QAC/C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IACpF,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,MAAM,CACX,cAAc,CAAC;YACb,IAAI,EAAE,0BAA0B,CAAC,iBAAiB;YAClD,OAAO,EACL,uFAAuF;YACzF,IAAI,EAAE,qEAAqE;SAC5E,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAEjD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,iFAAiF;QACjF,qFAAqF;QACrF,iFAAiF;QACjF,qFAAqF;QACrF,sFAAsF;QACtF,gDAAgD;QAChD,IAAI,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,UAAU,IAAI,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAClF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;QACpF,CAAC;QACD,OAAO,MAAM,CACX,cAAc,CAAC;YACb,IAAI,EAAE,0BAA0B,CAAC,iBAAiB;YAClD,OAAO,EAAE,IAAI,IAAI,4FAA4F;YAC7G,IAAI;YACJ,IAAI,EAAE,yEAAyE;SAChF,CAAC,CACH,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC3F,CAAC;IAED,MAAM,EAAE,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjD,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,OAAO,MAAM,CACX,cAAc,CAAC;YACb,IAAI,EAAE,0BAA0B,CAAC,gBAAgB;YACjD,OAAO,EAAE,IAAI,MAAM,CAAC,IAAI,gEAAgE;YACxF,IAAI,EAAE,MAAM,CAAC,IAAI;SAClB,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,MAAM,CACX,cAAc,CAAC;YACb,IAAI,EAAE,0BAA0B,CAAC,gBAAgB;YACjD,OAAO,EAAE,IAAI,MAAM,CAAC,IAAI,0DAA0D;YAClF,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,IAAI,EAAE,0CAA0C;SACjD,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACnD,OAAO,MAAM,CACX,cAAc,CAAC;YACb,IAAI,EAAE,0BAA0B,CAAC,sBAAsB;YACvD,OAAO,EAAE,IAAI,EAAE,sCAAsC,MAAM,CAAC,IAAI,sDAAsD;YACtH,IAAI,EAAE,EAAE;YACR,IAAI,EAAE,0DAA0D;SACjE,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,KAAK,SAAS,CAAC;IACvC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,cAAc,GAAoB;QACtC,IAAI,EAAE,EAAE;QACR,KAAK,EAAE,UAAU;QACjB,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;KAC1C,CAAC;IAEF,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,EAAE;QACF,OAAO;QACP,MAAM;QACN,QAAQ,EAAE;YACR,eAAe,EAAE,QAAQ,CAAC,eAAe;YACzC,WAAW,EAAE,QAAQ,CAAC,WAAW;YACjC,KAAK,EAAE,UAAU,CAAC;gBAChB,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;gBACjF,cAAc;aACf,CAAC;YACF,kFAAkF;YAClF,0EAA0E;YAC1E,OAAO,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;SACjE;QACD,WAAW,EAAE,EAAE;KAChB,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -16,13 +16,17 @@ export type { GeneratorDiagnostic, GeneratorDiagnosticCode } from './diagnostics
16
16
  export { GENERATOR_DIAGNOSTIC_CODES, generatorError, generatorWarning, withFile, } from './diagnostics.js';
17
17
  export type { DriftedFile, RegenerationAction, RegenerationOptions, RegenerationReport, RegenerationResult, RegenerationSink, } from './drift.js';
18
18
  export { checkDrift, formatRegenerationSummary, generatedFiles, hasDrift, planRegeneration, regenerate, staleGeneratedFiles, } from './drift.js';
19
+ export type { EjectRequest, EjectResult, EjectStatus, ManagedPathOptions } from './eject.js';
20
+ export { businessPathFor, eject } from './eject.js';
19
21
  export type { EmitsAgainst, GeneratorManifest, GeneratorManifestInput, GeneratorOutput, ManifestParseResult, Orchestration, StructuredOutput, TracingBackend, } from './manifest.js';
20
22
  export { checkIRSupport, GENERATOR_MANIFEST_VERSION, managedRoots, ORCHESTRATIONS, parseManifest, parseManifestJson, STRUCTURED_OUTPUTS, supportsIR, TRACING_BACKENDS, targetCapabilityDeclarations, validateGeneratorSet, validateManifest, } from './manifest.js';
21
23
  export { createMemorySink, createNodeSink } from './node-sink.js';
22
24
  export type { FileOwner } from './ownership.js';
23
- export { DEFAULT_BUSINESS_DIR, DEFAULT_GENERATED_DIR, DEFAULT_MANIFEST_FILENAME, escapesRoot, isAbsolutePath, isBusinessPath, isGeneratedPath, isRelativePath, isReservedPath, normalizeRelativePath, ownerForPath, REJECTION_SUFFIX, rejectionPath, } from './ownership.js';
25
+ export { DEFAULT_BUSINESS_DIR, DEFAULT_GENERATED_DIR, DEFAULT_MANIFEST_FILENAME, escapesRoot, isAbsolutePath, isBusinessPath, isGeneratedPath, isRelativePath, isReservedPath, isScaffoldPath, normalizeRelativePath, ownerForPath, REJECTION_SUFFIX, rejectionPath, SCAFFOLD_PREFIXES, } from './ownership.js';
24
26
  export type { GeneratedFile, Generator, GeneratorContext, Plan, PlanValidationOptions, } from './plan.js';
25
27
  export { isRecord, validatePlan } from './plan.js';
28
+ export type { CiProfile, EvalProfile, EvalSuite } from './scaffold.js';
29
+ export { ACTION_PINS, CI_WORKFLOW_PATH, cliRangeFor, EVALS_WORKFLOW_PATH, scaffoldCi, scaffoldEvals, } from './scaffold.js';
26
30
  export type { Version } from './semver.js';
27
31
  export { compareVersions, formatVersion, isValidRange, isValidVersion, parseRange, parseVersion, satisfies, } from './semver.js';
28
32
  export { PY_FASTAPI_MANIFEST, PY_FASTAPI_MANIFEST_INPUT, PY_FASTAPI_TARGET, phase0Generators, phase0TargetCapabilities, } from './targets.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,YAAY,EACV,WAAW,EACX,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAChG,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,SAAS,EACT,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,gBAAgB,EAChB,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,UAAU,EACV,yBAAyB,EACzB,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,4BAA4B,EAC5B,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,cAAc,EACd,cAAc,EACd,eAAe,EACf,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,IAAI,EACJ,qBAAqB,GACtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACnD,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,aAAa,EACb,YAAY,EACZ,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,YAAY,EACV,WAAW,EACX,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,SAAS,GACV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAChG,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,SAAS,EACT,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,gBAAgB,EAChB,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,UAAU,EACV,yBAAyB,EACzB,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACpD,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,4BAA4B,EAC5B,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,cAAc,EACd,cAAc,EACd,eAAe,EACf,cAAc,EACd,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,IAAI,EACJ,qBAAqB,GACtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACnD,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,mBAAmB,EACnB,UAAU,EACV,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,eAAe,EACf,aAAa,EACb,YAAY,EACZ,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -12,10 +12,12 @@ export { AID_MANIFEST_VERSION, emptyAidManifest, manifestFor, manifestRecordFor,
12
12
  export { checkDeterminism, compareIds, DETERMINISM_PATTERNS, ensureTrailingNewline, GENERATED_BANNER_MARKER, generatedBanner, normalizeNewlines, normalizeText, scanForNonDeterminism, sha256Hex, sortById, sortByPath, stableId, stableSortBy, } from './determinism.js';
13
13
  export { GENERATOR_DIAGNOSTIC_CODES, generatorError, generatorWarning, withFile, } from './diagnostics.js';
14
14
  export { checkDrift, formatRegenerationSummary, generatedFiles, hasDrift, planRegeneration, regenerate, staleGeneratedFiles, } from './drift.js';
15
+ export { businessPathFor, eject } from './eject.js';
15
16
  export { checkIRSupport, GENERATOR_MANIFEST_VERSION, managedRoots, ORCHESTRATIONS, parseManifest, parseManifestJson, STRUCTURED_OUTPUTS, supportsIR, TRACING_BACKENDS, targetCapabilityDeclarations, validateGeneratorSet, validateManifest, } from './manifest.js';
16
17
  export { createMemorySink, createNodeSink } from './node-sink.js';
17
- export { DEFAULT_BUSINESS_DIR, DEFAULT_GENERATED_DIR, DEFAULT_MANIFEST_FILENAME, escapesRoot, isAbsolutePath, isBusinessPath, isGeneratedPath, isRelativePath, isReservedPath, normalizeRelativePath, ownerForPath, REJECTION_SUFFIX, rejectionPath, } from './ownership.js';
18
+ export { DEFAULT_BUSINESS_DIR, DEFAULT_GENERATED_DIR, DEFAULT_MANIFEST_FILENAME, escapesRoot, isAbsolutePath, isBusinessPath, isGeneratedPath, isRelativePath, isReservedPath, isScaffoldPath, normalizeRelativePath, ownerForPath, REJECTION_SUFFIX, rejectionPath, SCAFFOLD_PREFIXES, } from './ownership.js';
18
19
  export { isRecord, validatePlan } from './plan.js';
20
+ export { ACTION_PINS, CI_WORKFLOW_PATH, cliRangeFor, EVALS_WORKFLOW_PATH, scaffoldCi, scaffoldEvals, } from './scaffold.js';
19
21
  export { compareVersions, formatVersion, isValidRange, isValidVersion, parseRange, parseVersion, satisfies, } from './semver.js';
20
22
  export { PY_FASTAPI_MANIFEST, PY_FASTAPI_MANIFEST_INPUT, PY_FASTAPI_TARGET, phase0Generators, phase0TargetCapabilities, } from './targets.js';
21
23
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,SAAS,EACT,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,gBAAgB,EAChB,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAS1B,OAAO,EACL,UAAU,EACV,yBAAyB,EACzB,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAWpB,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,4BAA4B,EAC5B,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,cAAc,EACd,cAAc,EACd,eAAe,EACf,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,aAAa,GACd,MAAM,gBAAgB,CAAC;AAQxB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EACL,eAAe,EACf,aAAa,EACb,YAAY,EACZ,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,SAAS,EACT,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,gBAAgB,EAChB,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAS1B,OAAO,EACL,UAAU,EACV,yBAAyB,EACzB,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAWpD,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,4BAA4B,EAC5B,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,cAAc,EACd,cAAc,EACd,eAAe,EACf,cAAc,EACd,cAAc,EACd,cAAc,EACd,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAQxB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,mBAAmB,EACnB,UAAU,EACV,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,eAAe,EACf,aAAa,EACb,YAAY,EACZ,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,cAAc,CAAC"}
@@ -1,14 +1,26 @@
1
1
  /**
2
2
  * Ownership and path rules (§8.3, §8.4, §10).
3
3
  *
4
- * The three-tier split is the whole reason regeneration is safe: `generated/` is
4
+ * The tier split is the whole reason regeneration is safe: `generated/` is
5
5
  * generator-owned and never hand-edited, `business/` is developer-owned and written
6
6
  * once, and the ownership of a path is decided by *where it lives*, not by what a
7
7
  * generator happens to say about it. Every path in a plan is normalized through this
8
8
  * module, so a generator cannot escape its own root or claim a business path as
9
9
  * generated (or the reverse).
10
+ *
11
+ * `scaffold` is the third tier: generator-authored content that lives *outside* the
12
+ * managed roots, which today means the repository's own CI workflows. It is written
13
+ * once and then belongs to the developer, so it is never recorded in the manifest --
14
+ * there is no hash to compare against, and claiming one would make every edit a drift
15
+ * conflict. The allowlist exists so that "outside the managed roots" does not become
16
+ * "anywhere": a generator may only reach paths it is explicitly permitted to own.
17
+ */
18
+ export type FileOwner = 'generated' | 'business' | 'scaffold';
19
+ /**
20
+ * The only path prefixes a generator may scaffold. A prefix, not a glob, so the check
21
+ * stays a string comparison and a generator cannot smuggle a nested escape past it.
10
22
  */
11
- export type FileOwner = 'generated' | 'business';
23
+ export declare const SCAFFOLD_PREFIXES: readonly ['.github/workflows/'];
12
24
  export declare const DEFAULT_GENERATED_DIR = "generated";
13
25
  export declare const DEFAULT_BUSINESS_DIR = "business";
14
26
  /** The ownership manifest. Generator bookkeeping, so it is never a planned artifact. */
@@ -35,6 +47,11 @@ export declare function ownerForPath(path: string, options?: {
35
47
  generatedDir?: string;
36
48
  businessDir?: string;
37
49
  }): FileOwner | undefined;
50
+ /**
51
+ * True for a path inside the scaffold allowlist. Requires a file name after the
52
+ * prefix: `.github/workflows/` itself is the directory, not a workflow.
53
+ */
54
+ export declare function isScaffoldPath(path: string): boolean;
38
55
  export declare function isGeneratedPath(path: string, options?: {
39
56
  generatedDir?: string;
40
57
  businessDir?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ownership.d.ts","sourceRoot":"","sources":["../src/ownership.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAEjD,eAAO,MAAM,qBAAqB,cAAc,CAAC;AACjD,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C,wFAAwF;AACxF,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAE7D,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUtE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,qFAAqF;AACrF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGjD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGpD;AAUD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,SAAS,GAAG,SAAS,CAUvB;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,OAAO,CAET;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,OAAO,CAET;AAED,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAI9E"}
1
+ {"version":3,"file":"ownership.d.ts","sourceRoot":"","sources":["../src/ownership.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,iBAAiB,YAAI,oBAAoB,CAAU,CAAC;AAEjE,eAAO,MAAM,qBAAqB,cAAc,CAAC;AACjD,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C,wFAAwF;AACxF,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAE7D,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUtE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,qFAAqF;AACrF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGjD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGpD;AAUD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,SAAS,GAAG,SAAS,CAWvB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMpD;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,OAAO,CAET;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,OAAO,CAET;AAED,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAI9E"}
package/dist/ownership.js CHANGED
@@ -1,13 +1,25 @@
1
1
  /**
2
2
  * Ownership and path rules (§8.3, §8.4, §10).
3
3
  *
4
- * The three-tier split is the whole reason regeneration is safe: `generated/` is
4
+ * The tier split is the whole reason regeneration is safe: `generated/` is
5
5
  * generator-owned and never hand-edited, `business/` is developer-owned and written
6
6
  * once, and the ownership of a path is decided by *where it lives*, not by what a
7
7
  * generator happens to say about it. Every path in a plan is normalized through this
8
8
  * module, so a generator cannot escape its own root or claim a business path as
9
9
  * generated (or the reverse).
10
+ *
11
+ * `scaffold` is the third tier: generator-authored content that lives *outside* the
12
+ * managed roots, which today means the repository's own CI workflows. It is written
13
+ * once and then belongs to the developer, so it is never recorded in the manifest --
14
+ * there is no hash to compare against, and claiming one would make every edit a drift
15
+ * conflict. The allowlist exists so that "outside the managed roots" does not become
16
+ * "anywhere": a generator may only reach paths it is explicitly permitted to own.
17
+ */
18
+ /**
19
+ * The only path prefixes a generator may scaffold. A prefix, not a glob, so the check
20
+ * stays a string comparison and a generator cannot smuggle a nested escape past it.
10
21
  */
22
+ export const SCAFFOLD_PREFIXES = ['.github/workflows/'];
11
23
  export const DEFAULT_GENERATED_DIR = 'generated';
12
24
  export const DEFAULT_BUSINESS_DIR = 'business';
13
25
  /** The ownership manifest. Generator bookkeeping, so it is never a planned artifact. */
@@ -68,8 +80,20 @@ export function ownerForPath(path, options = {}) {
68
80
  return 'generated';
69
81
  if (normalized === businessDir || normalized.startsWith(`${businessDir}/`))
70
82
  return 'business';
83
+ if (isScaffoldPath(normalized))
84
+ return 'scaffold';
71
85
  return undefined;
72
86
  }
87
+ /**
88
+ * True for a path inside the scaffold allowlist. Requires a file name after the
89
+ * prefix: `.github/workflows/` itself is the directory, not a workflow.
90
+ */
91
+ export function isScaffoldPath(path) {
92
+ const normalized = normalizeRelativePath(path);
93
+ if (normalized === undefined)
94
+ return false;
95
+ return SCAFFOLD_PREFIXES.some((prefix) => normalized.startsWith(prefix) && normalized.length > prefix.length);
96
+ }
73
97
  export function isGeneratedPath(path, options = {}) {
74
98
  return ownerForPath(path, options) === 'generated';
75
99
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ownership.js","sourceRoot":"","sources":["../src/ownership.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ownership.js","sourceRoot":"","sources":["../src/ownership.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Scaffold content: generator-authored files that live outside the managed roots (§6a).
3
+ *
4
+ * Today that is the repository's own CI. It is planned like any other file, but it is
5
+ * written once and then belongs to the developer: `aid gen` never overwrites it, never
6
+ * records it in the manifest, and `aid eject` reports it as already owned. That split is
7
+ * what makes a generated workflow usable -- CI has to be edited for a runner, a
8
+ * credential, or a second toolchain, and every one of those edits would otherwise be a
9
+ * drift conflict against a file the developer is supposed to own.
10
+ *
11
+ * The emitted workflow deliberately contains **no** `apply` step and no cloud keys: it
12
+ * gates the repository and stops there. Deployment stays a human action, per §12.6.
13
+ */
14
+ import type { GeneratedFile } from './plan.js';
15
+ /** The repository CI: the spec gates, then lint/build/test for the app tier. */
16
+ export declare const CI_WORKFLOW_PATH = ".github/workflows/ci.yml";
17
+ /**
18
+ * The eval gate. A separate workflow because it needs a model credential and therefore
19
+ * cannot be a required check on a fork pull request: it runs on `workflow_dispatch` and
20
+ * nightly, and reports a skip -- not a pass -- when the credential is absent.
21
+ */
22
+ export declare const EVALS_WORKFLOW_PATH = ".github/workflows/evals.yml";
23
+ /**
24
+ * Action pins. A tag is mutable; a SHA is not, and a generated workflow that runs
25
+ * `@v4` is one force-push away from running different code than it did last week.
26
+ * These are the commits the `v4`/`v5` tags resolved to when this was written.
27
+ */
28
+ export declare const ACTION_PINS: {
29
+ readonly checkout: 'actions/checkout@11d5960a326750d5838078e36cf38b85af677262';
30
+ readonly setupNode: 'actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020';
31
+ readonly setupPython: 'actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065';
32
+ };
33
+ export interface CiProfile {
34
+ /** The target name, used in the workflow's title so a reader knows what generated it. */
35
+ readonly target: string;
36
+ /** Spec path relative to the repository root. */
37
+ readonly specPath: string;
38
+ /**
39
+ * The file that proves the app tier has dependencies to install.
40
+ * When it is absent the build job is *skipped*, not green: the repository has a spec
41
+ * but no application yet, and a check that passes because it never ran is the failure
42
+ * mode §6a exists to prevent.
43
+ */
44
+ readonly dependencyManifest: string;
45
+ /** Steps that put the language toolchain on the runner, as prepared YAML lines. */
46
+ readonly toolchain: readonly string[];
47
+ /** Shell lines that install the app's dependencies. */
48
+ readonly install: readonly string[];
49
+ /** Shell lines for lint/format. */
50
+ readonly lint: readonly string[];
51
+ /** Shell line for the type check or build. */
52
+ readonly build: string;
53
+ /** Shell line for the unit tests. */
54
+ readonly test: string;
55
+ }
56
+ /** One generated eval module and the command that runs it from the project root. */
57
+ export interface EvalSuite {
58
+ readonly id: string;
59
+ readonly command: string;
60
+ }
61
+ export interface EvalProfile {
62
+ /** The target name, used in the workflow's title so a reader knows what generated it. */
63
+ readonly target: string;
64
+ /** Spec path relative to the repository root. */
65
+ readonly specPath: string;
66
+ /** Steps that put the language toolchain on the runner, as prepared YAML lines. */
67
+ readonly toolchain: readonly string[];
68
+ /** Shell lines that install the app's dependencies. */
69
+ readonly install: readonly string[];
70
+ /** The CI-gated evals, in declaration order. Never empty when a workflow is emitted. */
71
+ readonly suites: readonly EvalSuite[];
72
+ /**
73
+ * Environment variables the generated gateway reads a model key from. When this is
74
+ * empty every model is a fake, so the gate runs unguarded. When it is not, the gate is
75
+ * skipped with a warning unless every one of them is set: a real model behind a gate
76
+ * cannot be measured without its credential.
77
+ */
78
+ readonly secrets: readonly string[];
79
+ }
80
+ /** `major.minor` of a semver string, used to pin the CLI a workflow installs. */
81
+ export declare function cliRangeFor(version: string): string;
82
+ /**
83
+ * The CI workflow for a generated project.
84
+ *
85
+ * The spec gates are the framework's own contract and always run. The app job needs the
86
+ * project's dependency manifest, and a job-level `if` cannot call `hashFiles`, so a small
87
+ * `detect` job probes for the file and the app job is skipped -- not green -- without it.
88
+ * The infra job is skipped the same way when `infra/` is absent, and it only compares the
89
+ * committed tree against the spec: `plan`/`apply` need credentials and stay human actions.
90
+ */
91
+ export declare function scaffoldCi(profile: CiProfile, cliRange: string): GeneratedFile;
92
+ /**
93
+ * The eval gate for a project whose spec declares `gate.ci: true` evals.
94
+ *
95
+ * It never runs on `pull_request`. The generated evals measure a real model: with no
96
+ * credential the gateway falls back to the fake provider, whose output does not satisfy
97
+ * the eval's JSON schema, and the gate fails. Requiring the key on PRs would therefore
98
+ * either leak a secret to forks or turn the gate red for every contributor, so the gate
99
+ * runs on `workflow_dispatch` and nightly instead, and a missing key is an **error**
100
+ * rather than a silent skip: a gate that is green because it never ran is the failure
101
+ * mode this whole tier exists to avoid.
102
+ */
103
+ export declare function scaffoldEvals(profile: EvalProfile): GeneratedFile;
104
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,6BAA6B,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,gCAAgC,CAAC;AAEjE;;;;GAIG;AACH,eAAO,MAAM,WAAW;aACtB,QAAQ,EAAE,2DAA2D;aACrE,SAAS,EAAE,6DAA6D;aACxE,WAAW,EAAE,+DAA+D;CACpE,CAAC;AAEX,MAAM,WAAW,SAAS;IACxB,yFAAyF;IACzF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,mCAAmC;IACnC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,oFAAoF;AACpF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,yFAAyF;IACzF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CA2G9E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,CAqFjE"}