@stream44.studio/t44 0.4.0-rc.24
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/.dco-signatures +9 -0
- package/.github/workflows/dco.yaml +12 -0
- package/.github/workflows/gordian-open-integrity.yaml +13 -0
- package/.github/workflows/test.yaml +31 -0
- package/.o/GordianOpenIntegrity-CurrentLifehash.svg +1026 -0
- package/.o/GordianOpenIntegrity-InceptionLifehash.svg +1026 -0
- package/.o/GordianOpenIntegrity.yaml +21 -0
- package/.o/assets/Hero-Terminal44-v0.jpeg +0 -0
- package/.o/stream44.studio/assets/Icon-v1.svg +1170 -0
- package/.repo-identifier +1 -0
- package/DCO.md +34 -0
- package/LICENSE.txt +186 -0
- package/README.md +189 -0
- package/bin/activate +36 -0
- package/bin/activate.ts +30 -0
- package/bin/postinstall.sh +19 -0
- package/bin/shell +27 -0
- package/bin/t44 +27 -0
- package/caps/ConfigSchemaStruct.ts +55 -0
- package/caps/Home.ts +57 -0
- package/caps/HomeRegistry.ts +319 -0
- package/caps/HomeRegistryFile.ts +144 -0
- package/caps/JsonSchemas.ts +220 -0
- package/caps/OpenApiSchema.ts +67 -0
- package/caps/PackageDescriptor.ts +88 -0
- package/caps/ProjectCatalogs.ts +153 -0
- package/caps/ProjectDeployment.ts +426 -0
- package/caps/ProjectDevelopment.ts +257 -0
- package/caps/ProjectPublishing.ts +654 -0
- package/caps/ProjectPulling.ts +234 -0
- package/caps/ProjectRack.ts +155 -0
- package/caps/ProjectRepository.ts +332 -0
- package/caps/ProjectTest.ts +251 -0
- package/caps/ProjectTestLib.ts +257 -0
- package/caps/RootKey.ts +219 -0
- package/caps/SigningKey.ts +243 -0
- package/caps/TaskWorkflow.ts +192 -0
- package/caps/WorkspaceCli.ts +448 -0
- package/caps/WorkspaceConfig.ts +268 -0
- package/caps/WorkspaceConfig.yaml +87 -0
- package/caps/WorkspaceConfigFile.ts +902 -0
- package/caps/WorkspaceConnection.ts +329 -0
- package/caps/WorkspaceEntityConfig.ts +78 -0
- package/caps/WorkspaceEntityConfig.v0.ts +77 -0
- package/caps/WorkspaceEntityFact.ts +218 -0
- package/caps/WorkspaceInfo.ts +619 -0
- package/caps/WorkspaceInit.ts +30 -0
- package/caps/WorkspaceKey.ts +338 -0
- package/caps/WorkspaceModel.ts +373 -0
- package/caps/WorkspaceProjects.ts +636 -0
- package/caps/WorkspacePrompt.ts +430 -0
- package/caps/WorkspaceShell.sh +39 -0
- package/caps/WorkspaceShell.ts +104 -0
- package/caps/WorkspaceShell.yaml +64 -0
- package/caps/WorkspaceShellCli.ts +109 -0
- package/caps/patterns/README.md +2 -0
- package/caps/patterns/git-scm.com/ProjectPublishing.ts +507 -0
- package/caps/patterns/semver.org/ProjectPublishing.ts +458 -0
- package/docs/Overview.drawio +248 -0
- package/docs/Overview.svg +4 -0
- package/examples/01-Lifecycle/main.test.ts +223 -0
- package/lib/crypto.ts +53 -0
- package/lib/key.ts +381 -0
- package/lib/schema-console-renderer.ts +181 -0
- package/lib/schema-resolver.ts +349 -0
- package/lib/ucan.ts +137 -0
- package/package.json +91 -0
- package/standalone-rt.test.ts +150 -0
- package/standalone-rt.ts +140 -0
- package/structs/HomeRegistry.ts +55 -0
- package/structs/HomeRegistryConfig.ts +60 -0
- package/structs/ProjectCatalogsConfig.ts +53 -0
- package/structs/ProjectDeploymentConfig.ts +56 -0
- package/structs/ProjectDeploymentFact.ts +106 -0
- package/structs/ProjectPublishingConfig.ts +78 -0
- package/structs/ProjectPublishingFact.ts +68 -0
- package/structs/ProjectPullingConfig.ts +52 -0
- package/structs/ProjectRack.ts +51 -0
- package/structs/ProjectRackConfig.ts +56 -0
- package/structs/RepositoryOriginDescriptor.ts +51 -0
- package/structs/RootKeyConfig.ts +64 -0
- package/structs/SigningKeyConfig.ts +64 -0
- package/structs/Workspace.ts +56 -0
- package/structs/WorkspaceCatalogs.ts +56 -0
- package/structs/WorkspaceCliConfig.ts +53 -0
- package/structs/WorkspaceConfig.ts +64 -0
- package/structs/WorkspaceConfigFile.ts +50 -0
- package/structs/WorkspaceConfigFileMeta.ts +70 -0
- package/structs/WorkspaceKey.ts +55 -0
- package/structs/WorkspaceKeyConfig.ts +56 -0
- package/structs/WorkspaceMappingsConfig.ts +56 -0
- package/structs/WorkspaceProject.ts +104 -0
- package/structs/WorkspaceProjectsConfig.ts +67 -0
- package/structs/WorkspaceShellConfig.ts +83 -0
- package/structs/patterns/README.md +2 -0
- package/structs/patterns/git-scm.com/ProjectPublishingFact.ts +46 -0
- package/tsconfig.json +33 -0
- package/workspace-rt.ts +152 -0
- package/workspace.yaml +3 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
|
|
2
|
+
import { join, relative } from 'path'
|
|
3
|
+
import { readdir } from 'fs/promises'
|
|
4
|
+
import chalk from 'chalk'
|
|
5
|
+
import { Resolver } from '../lib/schema-resolver.js'
|
|
6
|
+
import type { ResolvedEntity } from '../lib/schema-resolver.js'
|
|
7
|
+
import { SchemaConsoleRenderer } from '../lib/schema-console-renderer.js'
|
|
8
|
+
|
|
9
|
+
export async function capsule({
|
|
10
|
+
encapsulate,
|
|
11
|
+
CapsulePropertyTypes,
|
|
12
|
+
makeImportStack
|
|
13
|
+
}: {
|
|
14
|
+
encapsulate: any
|
|
15
|
+
CapsulePropertyTypes: any
|
|
16
|
+
makeImportStack: any
|
|
17
|
+
}) {
|
|
18
|
+
return encapsulate({
|
|
19
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
20
|
+
'#@stream44.studio/encapsulate/structs/Capsule': {},
|
|
21
|
+
'#@stream44.studio/t44/structs/WorkspaceConfig': {
|
|
22
|
+
as: '$Config'
|
|
23
|
+
},
|
|
24
|
+
'#': {
|
|
25
|
+
Home: {
|
|
26
|
+
type: CapsulePropertyTypes.Mapping,
|
|
27
|
+
value: '@stream44.studio/t44/caps/Home'
|
|
28
|
+
},
|
|
29
|
+
WorkspaceConfig: {
|
|
30
|
+
type: CapsulePropertyTypes.Mapping,
|
|
31
|
+
value: '@stream44.studio/t44/caps/WorkspaceConfig'
|
|
32
|
+
},
|
|
33
|
+
HomeRegistry: {
|
|
34
|
+
type: CapsulePropertyTypes.Mapping,
|
|
35
|
+
value: '@stream44.studio/t44/caps/HomeRegistry'
|
|
36
|
+
},
|
|
37
|
+
run: {
|
|
38
|
+
type: CapsulePropertyTypes.Function,
|
|
39
|
+
value: async function (this: any, options?: { full?: boolean; entitySelector?: string }): Promise<void> {
|
|
40
|
+
const showFull = options?.full || false
|
|
41
|
+
const entitySelector = options?.entitySelector
|
|
42
|
+
|
|
43
|
+
const workspaceConfig = await this.$Config.config
|
|
44
|
+
const workspaceRootDir = workspaceConfig?.rootDir
|
|
45
|
+
const workspaceName = workspaceConfig?.name || 'default'
|
|
46
|
+
|
|
47
|
+
// Build resolver context with all required paths
|
|
48
|
+
const registryDir = await this.Home.registryDir
|
|
49
|
+
const foundationDir = join(workspaceRootDir, '.~o', 'workspace.foundation')
|
|
50
|
+
const homeRegistryConnectionsDir = join(registryDir, '@t44.sh~t44~caps~WorkspaceConnection', workspaceName)
|
|
51
|
+
|
|
52
|
+
const resolver = Resolver({
|
|
53
|
+
workspaceRootDir,
|
|
54
|
+
workspaceName,
|
|
55
|
+
schemasDir: join(foundationDir, '@t44.sh~t44~caps~JsonSchemas'),
|
|
56
|
+
factsDir: join(foundationDir, '@t44.sh~t44~caps~WorkspaceEntityFact'),
|
|
57
|
+
metaCacheDir: join(foundationDir, '@t44.sh~t44~caps~WorkspaceEntityFact', '@t44.sh~t44~structs~WorkspaceConfigFileMeta'),
|
|
58
|
+
homeRegistryConnectionsDir
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Load all entity types in parallel
|
|
62
|
+
const [schemas, configResult, factResult, connectionResult, registryEntities] = await Promise.all([
|
|
63
|
+
resolver.loadSchemas(),
|
|
64
|
+
resolver.loadConfigEntities(),
|
|
65
|
+
resolver.loadFactEntities(),
|
|
66
|
+
resolver.loadConnectionEntities(),
|
|
67
|
+
(async () => {
|
|
68
|
+
const registryRootDir = await this.HomeRegistry.rootDir
|
|
69
|
+
try {
|
|
70
|
+
const entries = await readdir(registryRootDir)
|
|
71
|
+
return {
|
|
72
|
+
rootDir: registryRootDir,
|
|
73
|
+
entities: entries
|
|
74
|
+
.filter((e: string) => e.startsWith('@'))
|
|
75
|
+
.map((e: string) => e.replace(/~/g, '/'))
|
|
76
|
+
}
|
|
77
|
+
} catch {
|
|
78
|
+
return { rootDir: registryRootDir, entities: [] }
|
|
79
|
+
}
|
|
80
|
+
})()
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
// Merge entity maps from individual loaders
|
|
84
|
+
const entities = new Map<string, ResolvedEntity[]>()
|
|
85
|
+
for (const [key, value] of configResult.entities) entities.set(key, value)
|
|
86
|
+
for (const [key, value] of factResult.entities) {
|
|
87
|
+
if (entities.has(key)) entities.get(key)!.push(...value)
|
|
88
|
+
else entities.set(key, value)
|
|
89
|
+
}
|
|
90
|
+
for (const [key, value] of connectionResult.entities) {
|
|
91
|
+
if (entities.has(key)) entities.get(key)!.push(...value)
|
|
92
|
+
else entities.set(key, value)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const configEntities = configResult.configEntities
|
|
96
|
+
const factEntities = factResult.factEntities
|
|
97
|
+
const connectionEntities = connectionResult.connectionEntities
|
|
98
|
+
const registryEntitySet = new Set(registryEntities.entities)
|
|
99
|
+
const registryRootDir = registryEntities.rootDir
|
|
100
|
+
|
|
101
|
+
// Build schema lookup: entity name (without #) → schema file path
|
|
102
|
+
const schemaMap = new Map<string, string>()
|
|
103
|
+
const schemasDir = join(workspaceRootDir, '.~o', 'workspace.foundation', '@t44.sh~t44~caps~JsonSchemas')
|
|
104
|
+
for (const [schemaId] of schemas) {
|
|
105
|
+
const entityName = schemaId.replace(/\.v\d+$/, '')
|
|
106
|
+
// Schema files don't include version in filename, only in $id
|
|
107
|
+
const schemaFileName = entityName.replace(/\//g, '~') + '.json'
|
|
108
|
+
const schemaPath = relative(workspaceRootDir, join(schemasDir, schemaFileName))
|
|
109
|
+
schemaMap.set(entityName, schemaPath)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Build unified entity list from all sources
|
|
113
|
+
const allEntities = new Set<string>()
|
|
114
|
+
for (const key of entities.keys()) allEntities.add(key)
|
|
115
|
+
for (const name of registryEntitySet) {
|
|
116
|
+
const key = name.startsWith('#') ? name : '#' + name
|
|
117
|
+
allEntities.add(key)
|
|
118
|
+
}
|
|
119
|
+
// Add schema-only entities (schemas without data)
|
|
120
|
+
// Skip if entity already has config/fact/connection/registry data
|
|
121
|
+
for (const entityName of schemaMap.keys()) {
|
|
122
|
+
const key = '#' + entityName
|
|
123
|
+
if (!entities.has(key) && !registryEntitySet.has(entityName)) {
|
|
124
|
+
allEntities.add(key)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Build entity matching function
|
|
129
|
+
const matchesSelector = (entity: string): boolean => {
|
|
130
|
+
if (!entitySelector) return true
|
|
131
|
+
|
|
132
|
+
const entityName = entity.startsWith('#') ? entity.substring(1) : entity
|
|
133
|
+
const schemaId = schemaMap.has(entityName) ? entityName : null
|
|
134
|
+
|
|
135
|
+
// Path-based matching (starts with '.')
|
|
136
|
+
if (entitySelector.startsWith('.')) {
|
|
137
|
+
const selectorPath = join(process.cwd(), entitySelector)
|
|
138
|
+
|
|
139
|
+
// Check config entities
|
|
140
|
+
const configInstances = entities.get(entity) || []
|
|
141
|
+
for (const instance of configInstances) {
|
|
142
|
+
if (instance.filePath.includes(selectorPath) || instance.relPath.includes(entitySelector)) {
|
|
143
|
+
return true
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Check fact entities
|
|
148
|
+
const facts = factEntities.get(entityName) || []
|
|
149
|
+
for (const fact of facts) {
|
|
150
|
+
if (fact.filePath.includes(selectorPath) || fact.relPath.includes(entitySelector)) {
|
|
151
|
+
return true
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Check connection entities
|
|
156
|
+
const connections = connectionEntities.get(entityName) || []
|
|
157
|
+
for (const conn of connections) {
|
|
158
|
+
if (conn.filePath.includes(selectorPath) || conn.relPath.includes(entitySelector)) {
|
|
159
|
+
return true
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Entity name matching (indexOf)
|
|
167
|
+
if (entityName.indexOf(entitySelector) !== -1) {
|
|
168
|
+
return true
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Schema ID matching (indexOf)
|
|
172
|
+
if (schemaId && schemaId.indexOf(entitySelector) !== -1) {
|
|
173
|
+
return true
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return false
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Filter entities based on selector
|
|
180
|
+
const filteredEntities = Array.from(allEntities).filter(matchesSelector).sort()
|
|
181
|
+
|
|
182
|
+
console.log('')
|
|
183
|
+
|
|
184
|
+
for (const entity of filteredEntities) {
|
|
185
|
+
const entityName = entity.startsWith('#') ? entity.substring(1) : entity
|
|
186
|
+
const isRegistry = registryEntitySet.has(entityName)
|
|
187
|
+
const isConfig = configEntities.has(entity)
|
|
188
|
+
const isFact = factEntities.has(entityName)
|
|
189
|
+
const isConnection = connectionEntities.has(entityName)
|
|
190
|
+
const hasSchema = schemaMap.has(entityName)
|
|
191
|
+
|
|
192
|
+
const schemaSuffix = hasSchema ? chalk.gray(' - ') + chalk.gray(schemaMap.get(entityName)!) : ''
|
|
193
|
+
|
|
194
|
+
// Collect validation status
|
|
195
|
+
const entityInstances = entities.get(entity) || []
|
|
196
|
+
const invalidInstances = entityInstances.filter(e => !e.valid)
|
|
197
|
+
const validationSuffix = invalidInstances.length > 0
|
|
198
|
+
? chalk.red(` ✗ ${invalidInstances.length} validation error(s)`)
|
|
199
|
+
: ''
|
|
200
|
+
|
|
201
|
+
// Skip schema-only display if entity also has registry/config/fact/connection data
|
|
202
|
+
// This prevents duplicate lines for entities like HomeRegistry
|
|
203
|
+
if (!isConfig && !isRegistry && !isFact && !isConnection) {
|
|
204
|
+
// Schema-only entity
|
|
205
|
+
if (hasSchema) {
|
|
206
|
+
console.log(chalk.gray(entityName) + schemaSuffix)
|
|
207
|
+
}
|
|
208
|
+
continue
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (isRegistry && !isConfig && !isFact && !isConnection) {
|
|
212
|
+
const dirName = entity.replace(/\//g, '~')
|
|
213
|
+
const registryPath = `${registryRootDir}/${dirName}`
|
|
214
|
+
console.log(chalk.bold.white(entityName) + ' ' + chalk.magenta('[registry]') + chalk.gray(' - ') + chalk.yellow(`${registryPath}/`) + schemaSuffix + validationSuffix)
|
|
215
|
+
} else if (isConfig) {
|
|
216
|
+
const configInstances = entityInstances.filter(e => e.filePath.endsWith('.yaml'))
|
|
217
|
+
if (configInstances.length > 0) {
|
|
218
|
+
const first = configInstances[0]
|
|
219
|
+
const lineInfo = first.line ? `:${first.line}` : ''
|
|
220
|
+
console.log(chalk.bold.white(entityName) + ' ' + chalk.cyan('[config]') + chalk.gray(' - ') + chalk.yellow(first.relPath + lineInfo) + schemaSuffix + validationSuffix)
|
|
221
|
+
} else {
|
|
222
|
+
console.log(chalk.bold.white(entityName) + ' ' + chalk.cyan('[config]') + schemaSuffix + validationSuffix)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (isRegistry) {
|
|
226
|
+
const dirName = entity.replace(/\//g, '~')
|
|
227
|
+
const registryPath = `${registryRootDir}/${dirName}`
|
|
228
|
+
console.log(chalk.magenta(' [registry]') + chalk.gray(' - ') + chalk.yellow(`${registryPath}/`))
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Show fact files
|
|
233
|
+
if (isFact) {
|
|
234
|
+
const facts = factEntities.get(entityName)!
|
|
235
|
+
if (!isConfig && !isRegistry && !isConnection) {
|
|
236
|
+
console.log(chalk.bold.white(entityName) + ' ' + chalk.green('[fact]') + schemaSuffix + validationSuffix)
|
|
237
|
+
} else {
|
|
238
|
+
console.log(chalk.green(' [fact]'))
|
|
239
|
+
}
|
|
240
|
+
for (let i = 0; i < facts.length; i++) {
|
|
241
|
+
const fact = facts[i]
|
|
242
|
+
const connector = i === facts.length - 1 ? '└── ' : '├── '
|
|
243
|
+
const indent = (isConfig || isRegistry || isConnection) ? ' ' : ' '
|
|
244
|
+
const validMark = fact.valid ? '' : chalk.red(' ✗')
|
|
245
|
+
console.log(chalk.gray(indent + connector) + chalk.green(fact.relPath) + chalk.gray(` (${fact.name})`) + validMark)
|
|
246
|
+
|
|
247
|
+
// Show full details for this specific file if --full flag is set
|
|
248
|
+
if (showFull) {
|
|
249
|
+
const schema = schemas.get(fact.schemaId)
|
|
250
|
+
const detailIndent = indent + ' '
|
|
251
|
+
|
|
252
|
+
if (schema) {
|
|
253
|
+
const rendered = SchemaConsoleRenderer.renderEntity(fact.data, schema, {
|
|
254
|
+
indent: detailIndent.length / 2,
|
|
255
|
+
maxDepth: -1,
|
|
256
|
+
showTypes: false
|
|
257
|
+
})
|
|
258
|
+
console.log(rendered)
|
|
259
|
+
} else {
|
|
260
|
+
const jsonLines = JSON.stringify(fact.data, null, 2).split('\n')
|
|
261
|
+
for (const line of jsonLines) {
|
|
262
|
+
console.log(chalk.gray(detailIndent + line))
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (fact.errors.length > 0) {
|
|
267
|
+
const errorLines = SchemaConsoleRenderer.renderErrors(fact.errors).split('\n')
|
|
268
|
+
for (const line of errorLines) {
|
|
269
|
+
console.log(detailIndent + line)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Show connection files
|
|
277
|
+
if (isConnection) {
|
|
278
|
+
const connections = connectionEntities.get(entityName)!
|
|
279
|
+
if (!isConfig && !isRegistry && !isFact) {
|
|
280
|
+
console.log(chalk.bold.white(entityName) + ' ' + chalk.magenta('[registry]') + schemaSuffix + validationSuffix)
|
|
281
|
+
} else {
|
|
282
|
+
console.log(chalk.magenta(' [registry]'))
|
|
283
|
+
}
|
|
284
|
+
for (let i = 0; i < connections.length; i++) {
|
|
285
|
+
const conn = connections[i]
|
|
286
|
+
const connector = i === connections.length - 1 ? '└── ' : '├── '
|
|
287
|
+
const indent = (isConfig || isRegistry || isFact) ? ' ' : ' '
|
|
288
|
+
const validMark = conn.valid ? '' : chalk.red(' ✗')
|
|
289
|
+
console.log(chalk.gray(indent + connector) + chalk.yellow(conn.relPath) + chalk.gray(` (${conn.name})`) + validMark)
|
|
290
|
+
|
|
291
|
+
// Show full details for this specific file if --full flag is set
|
|
292
|
+
if (showFull) {
|
|
293
|
+
const schema = schemas.get(conn.schemaId)
|
|
294
|
+
const detailIndent = indent + ' '
|
|
295
|
+
|
|
296
|
+
if (schema) {
|
|
297
|
+
// Connection data is wrapped in 'config' object, unwrap it for schema validation
|
|
298
|
+
const dataToRender = conn.data.config || conn.data
|
|
299
|
+
const rendered = SchemaConsoleRenderer.renderEntity(dataToRender, schema, {
|
|
300
|
+
indent: detailIndent.length / 2,
|
|
301
|
+
maxDepth: -1,
|
|
302
|
+
showTypes: false
|
|
303
|
+
})
|
|
304
|
+
console.log(rendered)
|
|
305
|
+
} else {
|
|
306
|
+
const jsonLines = JSON.stringify(conn.data, null, 2).split('\n')
|
|
307
|
+
for (const line of jsonLines) {
|
|
308
|
+
console.log(chalk.gray(detailIndent + line))
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (conn.errors.length > 0) {
|
|
313
|
+
const errorLines = SchemaConsoleRenderer.renderErrors(conn.errors).split('\n')
|
|
314
|
+
for (const line of errorLines) {
|
|
315
|
+
console.log(detailIndent + line)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Show validation errors in detail (for compact mode)
|
|
323
|
+
if (!showFull) {
|
|
324
|
+
for (const instance of invalidInstances) {
|
|
325
|
+
for (const err of instance.errors) {
|
|
326
|
+
console.log(chalk.red(` ${err.path}: ${err.message}`))
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Show full entity details for config entities if --full flag is set
|
|
332
|
+
if (showFull && isConfig && !isFact && !isConnection) {
|
|
333
|
+
const configInstances = entityInstances.filter(e => e.filePath.endsWith('.yaml'))
|
|
334
|
+
for (const instance of configInstances) {
|
|
335
|
+
const schema = schemas.get(instance.schemaId)
|
|
336
|
+
const baseIndent = ' '
|
|
337
|
+
|
|
338
|
+
if (schema) {
|
|
339
|
+
const rendered = SchemaConsoleRenderer.renderEntity(instance.data, schema, {
|
|
340
|
+
indent: baseIndent.length / 2 + 1,
|
|
341
|
+
maxDepth: -1,
|
|
342
|
+
showTypes: false
|
|
343
|
+
})
|
|
344
|
+
console.log(rendered)
|
|
345
|
+
} else {
|
|
346
|
+
const jsonLines = JSON.stringify(instance.data, null, 2).split('\n')
|
|
347
|
+
for (const line of jsonLines) {
|
|
348
|
+
console.log(chalk.gray(baseIndent + line))
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (instance.errors.length > 0) {
|
|
353
|
+
const errorLines = SchemaConsoleRenderer.renderErrors(instance.errors).split('\n')
|
|
354
|
+
for (const line of errorLines) {
|
|
355
|
+
console.log(baseIndent + line)
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
console.log('')
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}, {
|
|
368
|
+
importMeta: import.meta,
|
|
369
|
+
importStack: makeImportStack(),
|
|
370
|
+
capsuleName: capsule['#'],
|
|
371
|
+
})
|
|
372
|
+
}
|
|
373
|
+
capsule['#'] = '@stream44.studio/t44/caps/WorkspaceModel'
|