@toolproof-core/schema 1.0.9 → 1.0.11

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.
Files changed (67) hide show
  1. package/dist/generated/artifacts/constants.d.ts +121 -0
  2. package/dist/generated/artifacts/constants.js +121 -0
  3. package/dist/generated/artifacts/mappings.d.ts +23 -0
  4. package/dist/generated/artifacts/mappings.js +23 -0
  5. package/dist/generated/normalized/Genesis.json +117 -78
  6. package/dist/generated/resources/Genesis.json +489 -264
  7. package/dist/generated/schemas/Genesis.json +94 -61
  8. package/dist/generated/schemas/standalone/Job.json +9 -8
  9. package/dist/generated/schemas/standalone/RawStrategy.json +86 -110
  10. package/dist/generated/schemas/standalone/ResourceType.json +4 -4
  11. package/dist/generated/schemas/standalone/RunnableStrategy.json +115 -139
  12. package/dist/generated/schemas/standalone/StrategyRun.json +93 -117
  13. package/dist/generated/types/standalone/Resource_Genesis.d.ts +1 -1
  14. package/dist/generated/types/standalone/Resource_Job.d.ts +1 -1
  15. package/dist/generated/types/standalone/Resource_RawStrategy.d.ts +1 -1
  16. package/dist/generated/types/standalone/Resource_ResourceType.d.ts +1 -1
  17. package/dist/generated/types/standalone/Resource_RunnableStrategy.d.ts +1 -1
  18. package/dist/generated/types/types.d.ts +247 -239
  19. package/dist/index.d.ts +6 -3
  20. package/dist/index.js +5 -2
  21. package/dist/scripts/_lib/config.d.ts +3 -5
  22. package/dist/scripts/_lib/config.js +8 -14
  23. package/dist/scripts/generateConstantsAndMappings.d.ts +31 -0
  24. package/dist/scripts/generateConstantsAndMappings.js +243 -0
  25. package/dist/scripts/generateDependencies.js +1 -1
  26. package/dist/scripts/generateStandaloneType.js +2 -1
  27. package/dist/scripts/generateTerminals.js +2 -2
  28. package/dist/scripts/generateTypes.js +183 -5
  29. package/dist/scripts/wrapResourceTypesWithResourceShells.js +7 -3
  30. package/package.json +9 -10
  31. package/src/Genesis.json +1873 -1833
  32. package/src/generated/artifacts/constants.ts +122 -0
  33. package/src/generated/{dependencies → artifacts}/dependencyMap.json +282 -280
  34. package/src/generated/artifacts/mappings.ts +24 -0
  35. package/src/generated/{dependencies → artifacts}/terminals.json +13 -11
  36. package/src/generated/normalized/Genesis.json +1785 -1746
  37. package/src/generated/resources/Genesis.json +2833 -2608
  38. package/src/generated/schemas/Genesis.json +1348 -1315
  39. package/src/generated/schemas/standalone/Job.json +195 -194
  40. package/src/generated/schemas/standalone/RawStrategy.json +86 -110
  41. package/src/generated/schemas/standalone/ResourceType.json +106 -106
  42. package/src/generated/schemas/standalone/RunnableStrategy.json +645 -669
  43. package/src/generated/schemas/standalone/StrategyRun.json +913 -937
  44. package/src/generated/types/standalone/Resource_Genesis.d.ts +3 -3
  45. package/src/generated/types/standalone/Resource_Job.d.ts +3 -3
  46. package/src/generated/types/standalone/Resource_RawStrategy.d.ts +3 -3
  47. package/src/generated/types/standalone/Resource_ResourceType.d.ts +3 -3
  48. package/src/generated/types/standalone/Resource_RunnableStrategy.d.ts +3 -3
  49. package/src/generated/types/types.d.ts +717 -709
  50. package/src/index.ts +77 -70
  51. package/src/scripts/_lib/config.ts +207 -215
  52. package/src/scripts/extractSchemasFromResourceTypeShells.ts +261 -261
  53. package/src/scripts/generateConstantsAndMappings.ts +309 -0
  54. package/src/scripts/generateDependencies.ts +121 -121
  55. package/src/scripts/generateSchemaShims.ts +127 -127
  56. package/src/scripts/generateStandaloneSchema.ts +185 -185
  57. package/src/scripts/generateStandaloneType.ts +129 -127
  58. package/src/scripts/generateTerminals.ts +73 -73
  59. package/src/scripts/generateTypes.ts +733 -531
  60. package/src/scripts/normalizeAnchorsToPointers.ts +141 -141
  61. package/src/scripts/wrapResourceTypesWithResourceShells.ts +86 -82
  62. package/dist/generated/constants/constants.d.ts +0 -60
  63. package/dist/generated/constants/constants.js +0 -60
  64. package/dist/scripts/generateConstants.d.ts +0 -12
  65. package/dist/scripts/generateConstants.js +0 -179
  66. package/src/generated/constants/constants.ts +0 -61
  67. package/src/scripts/generateConstants.ts +0 -217
package/dist/index.d.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  export { default as SchemaGenesis } from './generated/schemas/Genesis.js';
2
+ export { default as SchemaResourceType } from './generated/schemas/standalone/ResourceType.js';
2
3
  export { default as SchemaJob } from './generated/schemas/standalone/Job.js';
4
+ export { default as SchemaRunnableStrategy } from './generated/schemas/standalone/RunnableStrategy.js';
3
5
  export { default as SchemaStrategyRun } from './generated/schemas/standalone/StrategyRun.js';
4
- export { default as ResourceTypeGenesis } from './generated/resources/Genesis.js';
5
- export { default as CONSTANTS } from './generated/constants/constants.js';
6
+ export { default as ResourceGenesis } from './generated/resources/Genesis.js';
7
+ export { default as CONSTANTS } from './generated/artifacts/constants.js';
8
+ export { default as MAPPINGS } from './generated/artifacts/mappings.js';
6
9
  export type { Resource_Genesis as Resource_GenesisJson } from './generated/types/standalone/Resource_Genesis.js';
7
10
  export type { Resource_ResourceType as Resource_ResourceTypeJson } from './generated/types/standalone/Resource_ResourceType.js';
8
11
  export type { Resource_Job as Resource_JobJson } from './generated/types/standalone/Resource_Job.js';
9
12
  export type { Resource_RawStrategy as Resource_RawStrategyJson } from './generated/types/standalone/Resource_RawStrategy.js';
10
13
  export type { Resource_RunnableStrategy as Resource_RunnableStrategyJson } from './generated/types/standalone/Resource_RunnableStrategy.js';
11
- export type { DocumentationFacet as DocumentationFacetJson, NucleusFacet as NucleusFacetJson, ResourceTypeIdentity as ResourceTypeIdentityJson, ResourceType as ResourceTypeJson, ResourceRoleIdentity as ResourceRoleIdentityJson, ResourceRoleValue as ResourceRoleValueJson, Conditional as ConditionalJson, RoleMap as RoleMapJson, Roles as RolesJson, RoleBindings as RoleBindingsJson, ResourceIdentity as ResourceIdentityJson, JobStepIdentity as JobStepIdentityJson, BranchStepIdentity as BranchStepIdentityJson, WhileStepIdentity as WhileStepIdentityJson, ForStepIdentity as ForStepIdentityJson, JobStep as JobStepJson, BranchStep as BranchStepJson, WhileStep as WhileStepJson, ForStep as ForStepJson, StepKind as StepKindJson, StepIdentity as StepIdentityJson, Step as StepJson, CreationContext as CreationContextJson, ResourceMissing as ResourceMissingJson, Resource as ResourceJson, StrategyState as StrategyStateJson, StepsFacet as StepsFacetJson, RawStrategy as RawStrategyJson, RunnableStrategyIdentity as RunnableStrategyIdentityJson, RunnableStrategyStatus as RunnableStrategyStatusJson, RunnableStrategy as RunnableStrategyJson, RunnableStrategyUpdate as RunnableStrategyUpdateJson, JobIdentity as JobIdentityJson, Job as JobJson, JsonData as JsonDataJson, StrategyThreadIdentity as StrategyThreadIdentityJson, StrategyThreadMap as StrategyThreadMapJson, JobStepSocket as JobStepSocketJson, Timestamp as TimestampJson, StrategyRunIdentity as StrategyRunIdentityJson, GoalIdentity as GoalIdentityJson, Goal as GoalJson, ShellMaterializedBase as ShellMaterializedBaseJson, } from './generated/types/types.js';
14
+ export type { DocumentationFacetJson, NucleusFacetJson, ResourceTypeIdentityJson, ResourceTypeJson, ResourceRoleIdentityJson, ResourceRoleValueJson, ResourceRoleJson, ConditionalJson, RoleDictJson, RolesJson, RoleBindingsJson, ResourceIdentityJson, JobStepIdentityJson, BranchStepIdentityJson, WhileStepIdentityJson, ForStepIdentityJson, JobStepJson, BranchStepJson, WhileStepJson, ForStepJson, StepKindJson, StepIdentityJson, StepJson, CreationContextJson, ResourceMissingJson, ResourceInputPotentialJson, ResourceOutputPotentialJson, ShellMaterializedBaseJson, ResourceJson, StrategyStateJson, StepsFacetJson, RawStrategyJson, RunnableStrategyIdentityJson, RunnableStrategyStatusJson, RunnableStrategyJson, RunnableStrategyUpdateJson, JobIdentityJson, JobJson, JsonDataJson, StrategyThreadIdentityJson, StrategyThreadDictJson, JobStepSocketJson, TimestampJson, StrategyRunIdentityJson, GoalIdentityJson, GoalJson, ErrorJson, } from './generated/types/types.js';
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  // Re-export JSON schemas via .ts shims to avoid .json re-exports in declarations
2
2
  export { default as SchemaGenesis } from './generated/schemas/Genesis.js';
3
+ export { default as SchemaResourceType } from './generated/schemas/standalone/ResourceType.js';
3
4
  export { default as SchemaJob } from './generated/schemas/standalone/Job.js';
5
+ export { default as SchemaRunnableStrategy } from './generated/schemas/standalone/RunnableStrategy.js';
4
6
  export { default as SchemaStrategyRun } from './generated/schemas/standalone/StrategyRun.js';
5
- export { default as ResourceTypeGenesis } from './generated/resources/Genesis.js';
6
- export { default as CONSTANTS } from './generated/constants/constants.js';
7
+ export { default as ResourceGenesis } from './generated/resources/Genesis.js';
8
+ export { default as CONSTANTS } from './generated/artifacts/constants.js';
9
+ export { default as MAPPINGS } from './generated/artifacts/mappings.js';
@@ -12,9 +12,8 @@ export declare class SchemaConfig {
12
12
  private readonly sourceFile;
13
13
  private readonly normalizedDir;
14
14
  private readonly schemasDir;
15
- private readonly constantsDir;
15
+ private readonly artifactsDir;
16
16
  private readonly resourcesDir;
17
- private readonly dependencyMapPath;
18
17
  private readonly typesSrcDir;
19
18
  private readonly typesDistDir;
20
19
  private readonly baseUrl;
@@ -29,8 +28,8 @@ export declare class SchemaConfig {
29
28
  getNormalizedSourcePath(): string;
30
29
  getSchemasDir(): string;
31
30
  getSchemaPath(filename: string): string;
32
- getConstantsDir(): string;
33
- getConstantsPath(filename: string): string;
31
+ getArtifactsDir(): string;
32
+ getArtifactsPath(filename: string): string;
34
33
  getStandaloneSchemaDir(): string;
35
34
  getStandaloneSchemaPath(filename: string): string;
36
35
  getTypesSrcDir(): string;
@@ -42,7 +41,6 @@ export declare class SchemaConfig {
42
41
  getStandaloneTypeSrcPath(filename: string): string;
43
42
  getStandaloneTypeDistPath(filename: string): string;
44
43
  getResourcesDir(): string;
45
- getDependencyMapPath(): string;
46
44
  getBaseUrl(): string;
47
45
  getVersion(): string;
48
46
  getSchemaId(schemaName: string): string;
@@ -22,13 +22,12 @@ export class SchemaConfig {
22
22
  this.sourceFile = getEnv('TP_SCHEMA_SOURCE_FILE', 'Genesis.json');
23
23
  this.normalizedDir = getEnv('TP_SCHEMA_NORMALIZED_DIR', 'src/generated/normalized');
24
24
  this.schemasDir = getEnv('TP_SCHEMA_SCHEMAS_DIR', 'src/generated/schemas');
25
- this.constantsDir = getEnv('TP_SCHEMA_CONSTANTS_DIR', 'src/generated/constants');
25
+ this.artifactsDir = getEnv('TP_SCHEMA_ARTIFACTS_DIR', 'src/generated/artifacts');
26
26
  this.resourcesDir = getEnv('TP_SCHEMA_RESOURCES_DIR', 'src/generated/resources');
27
- this.dependencyMapPath = getEnv('TP_SCHEMA_DEPENDENCY_MAP_PATH', 'src/generated/dependencies/dependencyMap.json');
28
27
  this.typesSrcDir = getEnv('TP_SCHEMA_TYPES_SRC_DIR', 'src/generated/types');
29
28
  this.typesDistDir = getEnv('TP_SCHEMA_TYPES_DIST_DIR', 'dist/generated/types');
30
29
  this.baseUrl = getEnv('TP_SCHEMA_BASE_URL', 'https://schemas.toolproof.com');
31
- this.version = getEnv('TP_SCHEMA_VERSION', 'v0');
30
+ this.version = getEnv('TP_SCHEMA_VERSION', 'v1');
32
31
  }
33
32
  // Path getters
34
33
  getRoot() {
@@ -67,13 +66,13 @@ export class SchemaConfig {
67
66
  getSchemaPath(filename) {
68
67
  return path.join(this.getSchemasDir(), filename);
69
68
  }
70
- getConstantsDir() {
71
- return path.isAbsolute(this.constantsDir)
72
- ? this.constantsDir
73
- : path.join(this.root, this.constantsDir);
69
+ getArtifactsDir() {
70
+ return path.isAbsolute(this.artifactsDir)
71
+ ? this.artifactsDir
72
+ : path.join(this.root, this.artifactsDir);
74
73
  }
75
- getConstantsPath(filename) {
76
- return path.join(this.getConstantsDir(), filename);
74
+ getArtifactsPath(filename) {
75
+ return path.join(this.getArtifactsDir(), filename);
77
76
  }
78
77
  getStandaloneSchemaDir() {
79
78
  return path.join(this.getSchemasDir(), 'standalone');
@@ -114,11 +113,6 @@ export class SchemaConfig {
114
113
  ? this.resourcesDir
115
114
  : path.join(this.root, this.resourcesDir);
116
115
  }
117
- getDependencyMapPath() {
118
- return path.isAbsolute(this.dependencyMapPath)
119
- ? this.dependencyMapPath
120
- : path.join(this.root, this.dependencyMapPath);
121
- }
122
116
  // Schema URL methods
123
117
  getBaseUrl() {
124
118
  return this.baseUrl;
@@ -0,0 +1,31 @@
1
+ export type GeneratedConstants = {
2
+ Names: Record<string, string>;
3
+ Enums: Record<string, Record<string, string>>;
4
+ };
5
+ export type GeneratedMappings = {
6
+ IdentityNameToIdentityPrefix: Record<string, string>;
7
+ StepKindToStepIdentityPrefix: Record<string, string>;
8
+ };
9
+ export type DeriveStepKindToStepIdentityPrefixResult = {
10
+ mapping: Record<string, string>;
11
+ missing: Array<{
12
+ stepKind: string;
13
+ identityName: string;
14
+ }>;
15
+ };
16
+ export declare function extractIdentityPrefixes(schema: unknown): Record<string, string>;
17
+ export declare function extractSubschemaNames(schema: unknown): Record<string, string>;
18
+ export declare function extractEnums(schema: unknown): Record<string, Record<string, string>>;
19
+ export declare function deriveStepKindToStepIdentityPrefix(enums: Record<string, Record<string, string>>, identityNameToIdentityPrefix: Record<string, string>): DeriveStepKindToStepIdentityPrefixResult;
20
+ export declare function extractGeneratedConstantsAndMappings(schema: unknown): {
21
+ CONSTANTS: GeneratedConstants;
22
+ MAPPINGS: GeneratedMappings;
23
+ DIAGNOSTICS: {
24
+ missingStepKindIdentityPrefixes: Array<{
25
+ stepKind: string;
26
+ identityName: string;
27
+ }>;
28
+ };
29
+ };
30
+ export declare function renderConstantsTs(constants: GeneratedConstants): string;
31
+ export declare function renderMappingsTs(mappings: GeneratedMappings): string;
@@ -0,0 +1,243 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { getConfig } from './_lib/config.js';
4
+ // PURE: Convert a string enum member into PascalCase.
5
+ // Examples: 'job' -> 'Job', 'graph_start' -> 'GraphStart'
6
+ function toPascalCase(value) {
7
+ return value
8
+ .split(/[^A-Za-z0-9]+/g)
9
+ .filter(Boolean)
10
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
11
+ .join('');
12
+ }
13
+ // PURE: Attempt to derive a canonical identity prefix from a canonical identity regex pattern.
14
+ function deriveIdentityPrefixFromPattern(pattern) {
15
+ // Canonical (currently used across schemas): ^PREFIX-.+$
16
+ const match = /^\^([^$]+)\.\+\$$/.exec(pattern);
17
+ if (!match)
18
+ return undefined;
19
+ const prefix = match[1];
20
+ if (!prefix || /[`\n\r]/.test(prefix))
21
+ return undefined;
22
+ return prefix;
23
+ }
24
+ // PURE: Extract all identity prefixes from `$defs/*Identity` string-pattern definitions.
25
+ export function extractIdentityPrefixes(schema) {
26
+ if (!schema || typeof schema !== 'object')
27
+ return {};
28
+ const defs = schema.$defs;
29
+ if (!defs || typeof defs !== 'object')
30
+ return {};
31
+ const defEntries = Object.entries(defs);
32
+ defEntries.sort(([a], [b]) => a.localeCompare(b));
33
+ const out = {};
34
+ for (const [defName, defVal] of defEntries) {
35
+ if (!/Identity$/.test(defName))
36
+ continue;
37
+ if (!defVal || typeof defVal !== 'object' || Array.isArray(defVal))
38
+ continue;
39
+ const v = defVal;
40
+ if (v.type !== 'string')
41
+ continue;
42
+ if (typeof v.pattern !== 'string')
43
+ continue;
44
+ const prefix = deriveIdentityPrefixFromPattern(v.pattern);
45
+ if (!prefix)
46
+ continue;
47
+ out[defName] = prefix;
48
+ }
49
+ return out;
50
+ }
51
+ // PURE: Extract all subschema names from `$defs/*`.
52
+ // Shape: { JobStep: 'JobStep', StepKind: 'StepKind', ... }
53
+ export function extractSubschemaNames(schema) {
54
+ if (!schema || typeof schema !== 'object')
55
+ return {};
56
+ const defs = schema.$defs;
57
+ if (!defs || typeof defs !== 'object')
58
+ return {};
59
+ const defEntries = Object.entries(defs);
60
+ defEntries.sort(([a], [b]) => a.localeCompare(b));
61
+ const out = {};
62
+ for (const [defName] of defEntries) {
63
+ if (!defName || /[\n\r`]/.test(defName))
64
+ continue;
65
+ out[defName] = defName;
66
+ }
67
+ return out;
68
+ }
69
+ // PURE: Extract all string enums from `$defs/*Kind|*Status` definitions.
70
+ // Shape: { StepKind: { job: 'job', ... }, ResourceShellKind: { inputPotential': 'inputPotential', ... } }
71
+ export function extractEnums(schema) {
72
+ if (!schema || typeof schema !== 'object')
73
+ return {};
74
+ const defs = schema.$defs;
75
+ if (!defs || typeof defs !== 'object')
76
+ return {};
77
+ const defEntries = Object.entries(defs);
78
+ defEntries.sort(([a], [b]) => a.localeCompare(b));
79
+ const out = {};
80
+ for (const [defName, defVal] of defEntries) {
81
+ if (!/(Kind|Status)$/.test(defName))
82
+ continue;
83
+ if (!defVal || typeof defVal !== 'object' || Array.isArray(defVal))
84
+ continue;
85
+ const v = defVal;
86
+ if (v.type !== 'string')
87
+ continue;
88
+ if (!Array.isArray(v.enum) || v.enum.length === 0)
89
+ continue;
90
+ if (v.enum.some((x) => typeof x !== 'string'))
91
+ continue;
92
+ const members = {};
93
+ for (const member of v.enum) {
94
+ members[member] = member;
95
+ }
96
+ out[defName] = members;
97
+ }
98
+ return out;
99
+ }
100
+ // PURE: Derive a StepKind -> StepIdentityPrefix mapping.
101
+ // Example: { job: 'job' } + IdentityNameToIdentityPrefix['JobStepIdentity']='JOB_STEP-' => { job: 'JOB_STEP-' }
102
+ export function deriveStepKindToStepIdentityPrefix(enums, identityNameToIdentityPrefix) {
103
+ const stepKindEnum = enums.StepKind;
104
+ if (!stepKindEnum || typeof stepKindEnum !== 'object')
105
+ return { mapping: {}, missing: [] };
106
+ const stepKinds = Object.keys(stepKindEnum).sort((a, b) => a.localeCompare(b));
107
+ const mapping = {};
108
+ const missing = [];
109
+ for (const stepKind of stepKinds) {
110
+ const identityName = `${toPascalCase(stepKind)}StepIdentity`;
111
+ const prefix = identityNameToIdentityPrefix[identityName];
112
+ if (!prefix) {
113
+ missing.push({ stepKind, identityName });
114
+ continue;
115
+ }
116
+ mapping[stepKind] = prefix;
117
+ }
118
+ return { mapping, missing };
119
+ }
120
+ // PURE: Extract generated CONSTANTS + MAPPINGS from a parsed schema.
121
+ export function extractGeneratedConstantsAndMappings(schema) {
122
+ const names = extractSubschemaNames(schema);
123
+ const enums = extractEnums(schema);
124
+ const identityPrefixes = extractIdentityPrefixes(schema);
125
+ const derivedStepKind = deriveStepKindToStepIdentityPrefix(enums, identityPrefixes);
126
+ return {
127
+ CONSTANTS: {
128
+ Names: names,
129
+ Enums: enums,
130
+ },
131
+ MAPPINGS: {
132
+ IdentityNameToIdentityPrefix: identityPrefixes,
133
+ StepKindToStepIdentityPrefix: derivedStepKind.mapping,
134
+ },
135
+ DIAGNOSTICS: {
136
+ missingStepKindIdentityPrefixes: derivedStepKind.missing,
137
+ },
138
+ };
139
+ }
140
+ // PURE: Render helpers for TS keys/strings.
141
+ function escapeTsString(value) {
142
+ return value
143
+ .replace(/\\/g, '\\\\')
144
+ .replace(/\r/g, '\\r')
145
+ .replace(/\n/g, '\\n')
146
+ .replace(/\t/g, '\\t')
147
+ .replace(/'/g, "\\'");
148
+ }
149
+ function renderTsStringLiteral(value) {
150
+ return `'${escapeTsString(value)}'`;
151
+ }
152
+ function isValidTsIdentifier(key) {
153
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key);
154
+ }
155
+ function renderTsKey(key) {
156
+ return isValidTsIdentifier(key) ? key : renderTsStringLiteral(key);
157
+ }
158
+ // PURE: Render constants TypeScript source.
159
+ export function renderConstantsTs(constants) {
160
+ const nameKeys = Object.keys(constants.Names).sort((a, b) => a.localeCompare(b));
161
+ const enumKeys = Object.keys(constants.Enums).sort((a, b) => a.localeCompare(b));
162
+ const lines = [];
163
+ lines.push('const CONSTANTS = {');
164
+ lines.push(' Names: {');
165
+ for (const key of nameKeys) {
166
+ const value = constants.Names[key] ?? '';
167
+ lines.push(` ${renderTsKey(key)}: ${renderTsStringLiteral(value)},`);
168
+ }
169
+ lines.push(' },');
170
+ lines.push(' Enums: {');
171
+ for (const key of enumKeys) {
172
+ const members = constants.Enums[key] ?? {};
173
+ lines.push(` ${renderTsKey(key)}: {`);
174
+ for (const memberKey of Object.keys(members)) {
175
+ const value = members[memberKey] ?? '';
176
+ lines.push(` ${renderTsKey(memberKey)}: ${renderTsStringLiteral(value)},`);
177
+ }
178
+ lines.push(' },');
179
+ }
180
+ lines.push(' }');
181
+ lines.push('} as const;');
182
+ lines.push('');
183
+ lines.push('export default CONSTANTS;');
184
+ lines.push('');
185
+ return lines.join('\n');
186
+ }
187
+ // PURE: Render mappings TypeScript source.
188
+ export function renderMappingsTs(mappings) {
189
+ const identityKeys = Object.keys(mappings.IdentityNameToIdentityPrefix).sort((a, b) => a.localeCompare(b));
190
+ const stepKindKeys = Object.keys(mappings.StepKindToStepIdentityPrefix).sort((a, b) => a.localeCompare(b));
191
+ const lines = [];
192
+ lines.push('const MAPPINGS = {');
193
+ lines.push(' IdentityNameToIdentityPrefix: {');
194
+ for (const key of identityKeys) {
195
+ const value = mappings.IdentityNameToIdentityPrefix[key] ?? '';
196
+ lines.push(` ${renderTsKey(key)}: ${renderTsStringLiteral(value)},`);
197
+ }
198
+ lines.push(' },');
199
+ lines.push(' StepKindToStepIdentityPrefix: {');
200
+ for (const key of stepKindKeys) {
201
+ const value = mappings.StepKindToStepIdentityPrefix[key] ?? '';
202
+ lines.push(` ${renderTsKey(key)}: ${renderTsStringLiteral(value)},`);
203
+ }
204
+ lines.push(' },');
205
+ lines.push('} as const;');
206
+ lines.push('');
207
+ lines.push('export default MAPPINGS;');
208
+ lines.push('');
209
+ return lines.join('\n');
210
+ }
211
+ // IMPURE: Script entrypoint (config + filesystem I/O + console + process exit code).
212
+ function main() {
213
+ try {
214
+ const config = getConfig();
215
+ const inPath = config.getSchemaPath('Genesis.json');
216
+ const outConstantsPath = config.getArtifactsPath('constants.ts');
217
+ const outMappingsPath = config.getArtifactsPath('mappings.ts');
218
+ if (!fs.existsSync(inPath)) {
219
+ throw new Error(`Genesis schema not found at ${inPath}. Run extractSchemasFromResourceTypeShells first.`);
220
+ }
221
+ const raw = fs.readFileSync(inPath, 'utf8');
222
+ const doc = JSON.parse(raw);
223
+ const { CONSTANTS, MAPPINGS, DIAGNOSTICS } = extractGeneratedConstantsAndMappings(doc);
224
+ if (DIAGNOSTICS.missingStepKindIdentityPrefixes.length) {
225
+ const rows = DIAGNOSTICS.missingStepKindIdentityPrefixes
226
+ .map(({ stepKind, identityName }) => `${stepKind} -> ${identityName}`)
227
+ .join(', ');
228
+ throw new Error(`Missing IdentityNameToIdentityPrefix entries required for StepKindToStepIdentityPrefix: ${rows}`);
229
+ }
230
+ const constantsTs = renderConstantsTs(CONSTANTS);
231
+ const mappingsTs = renderMappingsTs(MAPPINGS);
232
+ fs.mkdirSync(path.dirname(outConstantsPath), { recursive: true });
233
+ fs.writeFileSync(outConstantsPath, constantsTs, 'utf8');
234
+ fs.writeFileSync(outMappingsPath, mappingsTs, 'utf8');
235
+ console.log(`Wrote constants to ${outConstantsPath}`);
236
+ console.log(`Wrote mappings to ${outMappingsPath}`);
237
+ }
238
+ catch (error) {
239
+ console.error(`Error generating constants/mappings: ${error?.message ?? error}`);
240
+ process.exitCode = 1;
241
+ }
242
+ }
243
+ main();
@@ -88,7 +88,7 @@ function main() {
88
88
  try {
89
89
  const config = getConfig();
90
90
  const inPath = config.getSchemaPath("Genesis.json");
91
- const outPath = config.getDependencyMapPath();
91
+ const outPath = config.getArtifactsPath("dependencyMap.json");
92
92
  if (!fs.existsSync(inPath)) {
93
93
  throw new Error(`Genesis schema not found at ${inPath}. Run extractSchemasFromResourceTypeShells first.`);
94
94
  }
@@ -9,7 +9,8 @@ import { getConfig } from "./_lib/config.js";
9
9
  // PURE: Generate the content of a standalone Resource type definition file for a given schema name.
10
10
  function generateStandaloneTypeLogic(name) {
11
11
  const header = "// Auto-generated strict composite type. Do not edit.\n";
12
- const ts = `import type { ShellMaterializedBase, ${name} as NucleusSchema } from "../types.js";\n` +
12
+ const nucleusTypeName = name.endsWith("Json") ? name : `${name}Json`;
13
+ const ts = `import type { ShellMaterializedBaseJson as ShellMaterializedBase, ${nucleusTypeName} as NucleusSchema } from "../types.js";\n` +
13
14
  `export type Resource_${name} = ShellMaterializedBase & { nucleus: NucleusSchema };\n`;
14
15
  return header + ts;
15
16
  }
@@ -37,8 +37,8 @@ function computeTerminalsInKeyOrder(dependencyMap) {
37
37
  function main() {
38
38
  try {
39
39
  const config = getConfig();
40
- const inPath = config.getDependencyMapPath();
41
- const outPath = path.join(path.dirname(inPath), "terminals.json");
40
+ const inPath = config.getArtifactsPath("dependencyMap.json");
41
+ const outPath = config.getArtifactsPath("terminals.json");
42
42
  if (!fs.existsSync(inPath)) {
43
43
  throw new Error(`Dependency map not found at ${inPath}. Run generateDependencies first.`);
44
44
  }
@@ -227,6 +227,178 @@ function removeDuplicateUnionEntries(ts) {
227
227
  function escapeRegExpLiteral(value) {
228
228
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
229
229
  }
230
+ // PURE: Rename exported top-level generated declarations to canonical `*Json` names.
231
+ // This makes editor hover/inference prefer `FooJson` because the underlying declared
232
+ // symbol is `FooJson` (not `Foo` with a re-export alias).
233
+ function applyReplacementsOutsideStringsAndComments(text, replaceCodeSegment) {
234
+ const len = text.length;
235
+ let out = '';
236
+ let i = 0;
237
+ let codeStart = 0;
238
+ const flushCode = (end) => {
239
+ if (end > codeStart)
240
+ out += replaceCodeSegment(text.slice(codeStart, end));
241
+ codeStart = end;
242
+ };
243
+ const startsWith = (s) => text.startsWith(s, i);
244
+ while (i < len) {
245
+ // Line comment
246
+ if (startsWith('//')) {
247
+ flushCode(i);
248
+ const start = i;
249
+ i += 2;
250
+ while (i < len && text[i] !== '\n')
251
+ i++;
252
+ if (i < len && text[i] === '\n')
253
+ i++;
254
+ out += text.slice(start, i);
255
+ codeStart = i;
256
+ continue;
257
+ }
258
+ // Block comment
259
+ if (startsWith('/*')) {
260
+ flushCode(i);
261
+ const start = i;
262
+ i += 2;
263
+ while (i < len && !text.startsWith('*/', i))
264
+ i++;
265
+ if (i < len)
266
+ i += 2;
267
+ out += text.slice(start, i);
268
+ codeStart = i;
269
+ continue;
270
+ }
271
+ const ch = text[i];
272
+ // Single-quoted string
273
+ if (ch === "'") {
274
+ flushCode(i);
275
+ const start = i;
276
+ i++;
277
+ while (i < len) {
278
+ const c = text[i];
279
+ if (c === '\\') {
280
+ i += 2;
281
+ continue;
282
+ }
283
+ i++;
284
+ if (c === "'")
285
+ break;
286
+ }
287
+ out += text.slice(start, i);
288
+ codeStart = i;
289
+ continue;
290
+ }
291
+ // Double-quoted string
292
+ if (ch === '"') {
293
+ flushCode(i);
294
+ const start = i;
295
+ i++;
296
+ while (i < len) {
297
+ const c = text[i];
298
+ if (c === '\\') {
299
+ i += 2;
300
+ continue;
301
+ }
302
+ i++;
303
+ if (c === '"')
304
+ break;
305
+ }
306
+ out += text.slice(start, i);
307
+ codeStart = i;
308
+ continue;
309
+ }
310
+ // Template literal (backticks). We conservatively treat the whole template as a string.
311
+ // The generated .d.ts uses these primarily for template-literal *value* types like `TYPE-${string}`
312
+ // and we do not want to rewrite their raw text.
313
+ if (ch === '`') {
314
+ flushCode(i);
315
+ const start = i;
316
+ i++;
317
+ while (i < len) {
318
+ const c = text[i];
319
+ if (c === '\\') {
320
+ i += 2;
321
+ continue;
322
+ }
323
+ i++;
324
+ if (c === '`')
325
+ break;
326
+ }
327
+ out += text.slice(start, i);
328
+ codeStart = i;
329
+ continue;
330
+ }
331
+ i++;
332
+ }
333
+ flushCode(len);
334
+ return out;
335
+ }
336
+ function renameExportedTopLevelTypesToJson(tsText) {
337
+ // Collect exported type/interface names.
338
+ const exportedDeclRegex = /^export\s+(?:type|interface)\s+([A-Za-z_][A-Za-z0-9_]*)\b/gm;
339
+ const exportedNames = new Set();
340
+ for (let m = exportedDeclRegex.exec(tsText); m; m = exportedDeclRegex.exec(tsText)) {
341
+ exportedNames.add(m[1]);
342
+ }
343
+ const renamePairs = Array.from(exportedNames)
344
+ .filter((name) => !name.endsWith('Json'))
345
+ .map((name) => ({ from: name, to: `${name}Json` }));
346
+ if (!renamePairs.length)
347
+ return tsText;
348
+ // Replace longer names first to reduce any accidental partial-match risk.
349
+ renamePairs.sort((a, b) => b.from.length - a.from.length);
350
+ const replaceCode = (code) => {
351
+ let out = code;
352
+ for (const { from, to } of renamePairs) {
353
+ const re = new RegExp(`\\b${escapeRegExpLiteral(from)}\\b`, 'g');
354
+ out = out.replace(re, to);
355
+ }
356
+ return out;
357
+ };
358
+ return applyReplacementsOutsideStringsAndComments(tsText, replaceCode);
359
+ }
360
+ // PURE: Derive the TS value type for JobStepSocket from Genesis.json.
361
+ // We prefer to match the schema shape:
362
+ // JobStepSocket.additionalProperties.oneOf = [#ResourcePotential, #Resource]
363
+ // so the emitted TS becomes:
364
+ // Record<ResourceRoleIdentity, Resource | ResourcePotential>
365
+ function deriveJobStepSocketValueType(parsedSchema) {
366
+ // NOTE: The generator reads from `src/generated/schemas/Genesis.json`, where `$defs.*`
367
+ // entries are plain JSON-Schema objects.
368
+ // The source-of-truth `src/Genesis.json` uses a wrapper shape:
369
+ // $defs.X = { identity, name, description, nucleusSchema: { ...actual schema... } }
370
+ // Support both.
371
+ const defs = parsedSchema?.$defs ?? parsedSchema?.nucleusSchema?.$defs;
372
+ const def = defs?.JobStepSocket;
373
+ const schemaNode = def?.nucleusSchema ?? def;
374
+ const additionalProperties = schemaNode?.additionalProperties;
375
+ if (!additionalProperties || typeof additionalProperties !== 'object' || Array.isArray(additionalProperties)) {
376
+ return 'Resource';
377
+ }
378
+ const union = additionalProperties.oneOf ??
379
+ additionalProperties.anyOf;
380
+ if (!Array.isArray(union) || union.length === 0) {
381
+ return 'Resource';
382
+ }
383
+ const names = [];
384
+ for (const item of union) {
385
+ const ref = item && typeof item === 'object' ? item.$ref : undefined;
386
+ if (typeof ref !== 'string')
387
+ continue;
388
+ // Accept both internal anchor refs like "#Resource" and JSON Pointer refs like "#/$defs/Resource".
389
+ const m = /^#(?:\/(?:\$defs|definitions)\/)?([A-Za-z_][A-Za-z0-9_]*)$/.exec(ref);
390
+ if (m)
391
+ names.push(m[1]);
392
+ }
393
+ const unique = Array.from(new Set(names));
394
+ if (!unique.length)
395
+ return 'Resource';
396
+ // Preserve an intentional ordering when we recognize the canonical pair.
397
+ if (unique.includes('Resource') && unique.includes('ResourcePotential')) {
398
+ return 'Resource | ResourcePotential';
399
+ }
400
+ return unique.join(' | ');
401
+ }
230
402
  // PURE: Fix a known json-schema-to-typescript edge case where a JSON-like recursive value union
231
403
  // accidentally includes a direct self-reference (`| JsonData`) instead of the intended array case (`| JsonData[]`).
232
404
  function fixJsonDataSelfReference(ts) {
@@ -306,19 +478,25 @@ function postProcessEmittedTypes(ts, parsedSchema) {
306
478
  const resourceRoleKeyType = 'ResourceRoleIdentity';
307
479
  const jobStepKeyType = 'JobStepIdentity';
308
480
  const strategyThreadKeyType = 'StrategyThreadIdentity';
309
- ts = ts.replace(/export interface RoleMap\s*{[^}]*}/g, `export type RoleMap = Record<${resourceRoleKeyType}, ResourceRoleValue>;`);
481
+ ts = ts.replace(/export interface RoleDict\s*{[^}]*}/g, `export type RoleDict = Record<${resourceRoleKeyType}, ResourceRoleValue>;`);
310
482
  // Normalize StrategyState & related socket maps to identity-keyed Records.
311
483
  // These are emitted as `[k: string]` by json-schema-to-typescript but are identity-keyed in practice.
312
- // Per schema: JobStepSocket: Record<ResourceRoleIdentity, Resource>
484
+ // Per schema: JobStepSocket: Record<ResourceRoleIdentity, Resource | ResourcePotential>
313
485
  // StrategyState: Record<JobStepIdentity, JobStepSocket>
314
- const jobStepSocketValueType = 'Resource';
486
+ const jobStepSocketValueType = deriveJobStepSocketValueType(parsedSchema);
315
487
  ts = ts.replace(/export interface JobStepSocket\s*\{\s*\[k:\s*string\]:\s*[^;]+;\s*\}/g, `export type JobStepSocket = Record<${resourceRoleKeyType}, ${jobStepSocketValueType}>;`);
488
+ // If the upstream generator (or earlier passes) already emitted a Record-based alias,
489
+ // force its value type to match the schema-derived union.
490
+ ts = ts.replace(/export\s+type\s+JobStepSocket\s*=\s*Record<\s*ResourceRoleIdentity\s*,\s*[^>]+>\s*;/g, `export type JobStepSocket = Record<${resourceRoleKeyType}, ${jobStepSocketValueType}>;`);
316
491
  ts = ts.replace(/export interface StrategyState\s*\{\s*\[k:\s*string\]:\s*JobStepSocket;\s*\}/g, `export type StrategyState = Record<${jobStepKeyType}, JobStepSocket>;`);
317
492
  ts = ts.replace(/(strategyStateUpdate\??:\s*)\{\s*\[k:\s*string\]:\s*JobStepSocket;\s*\};/g, `$1Record<${jobStepKeyType}, JobStepSocket>;`);
318
- // Ensure key constraints for strategyThreadMap are preserved as template-literal identity keys.
493
+ // Ensure key constraints for strategyThreadDict are preserved as template-literal identity keys.
319
494
  // json-schema-to-typescript emits `[k: string]: StepArray;`, but we want keys to be `StrategyThreadIdentity`.
320
- ts = ts.replace(/export interface StrategyThreadMap\s*\{\s*\[k:\s*string\]:\s*StepArray;\s*\}/g, `export type StrategyThreadMap = Record<${strategyThreadKeyType}, StepArray>;`);
495
+ ts = ts.replace(/export interface StrategyThreadDict\s*\{\s*\[k:\s*string\]:\s*StepArray;\s*\}/g, `export type StrategyThreadDict = Record<${strategyThreadKeyType}, StepArray>;`);
321
496
  ts = fixJsonDataSelfReference(ts);
497
+ // IMPORTANT: do this last so earlier post-processing regexes can target
498
+ // the generator's original names (without `Json` suffixes).
499
+ ts = renameExportedTopLevelTypesToJson(ts);
322
500
  return ts;
323
501
  }
324
502
  // PURE: Add banner + formatting/guards to build the final .d.ts content.
@@ -22,8 +22,10 @@ function generateResourceShellLogic(genesis) {
22
22
  resourceRoleHandle: 'ROLE-Genesis',
23
23
  jobStepHandle: 'JOB_STEP-Genesis'
24
24
  },
25
- kind: 'materialized',
25
+ resourceShellKind: 'materialized',
26
+ version: 1,
26
27
  timestamp: genesisTimestamp,
28
+ path: 'https://schemas.toolproof.com/v1/Genesis.json',
27
29
  nucleus: {}
28
30
  };
29
31
  defKeys.forEach((defName) => {
@@ -33,10 +35,12 @@ function generateResourceShellLogic(genesis) {
33
35
  resourceTypeHandle: 'TYPE-ResourceType',
34
36
  creationContext: {
35
37
  resourceRoleHandle: 'ROLE-Genesis',
36
- jobStepHandle: `JOB_STEP-${defName}`
38
+ jobStepHandle: 'JOB_STEP-Genesis'
37
39
  },
38
- kind: 'materialized',
40
+ resourceShellKind: 'materialized',
41
+ version: 1,
39
42
  timestamp: genesisTimestamp,
43
+ path: `https://schemas.toolproof.com/v1/Genesis.json#/$defs/${defName}`,
40
44
  nucleus: defValue
41
45
  };
42
46
  });