@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,218 @@
|
|
|
1
|
+
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { mkdir, writeFile, readFile, stat } from 'fs/promises'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export async function capsule({
|
|
7
|
+
encapsulate,
|
|
8
|
+
CapsulePropertyTypes,
|
|
9
|
+
makeImportStack
|
|
10
|
+
}: {
|
|
11
|
+
encapsulate: any
|
|
12
|
+
CapsulePropertyTypes: any
|
|
13
|
+
makeImportStack: any
|
|
14
|
+
}) {
|
|
15
|
+
return encapsulate({
|
|
16
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
17
|
+
'#@stream44.studio/encapsulate/structs/Capsule': {},
|
|
18
|
+
'#': {
|
|
19
|
+
WorkspaceConfig: {
|
|
20
|
+
type: CapsulePropertyTypes.Mapping,
|
|
21
|
+
value: '@stream44.studio/t44/caps/WorkspaceConfig'
|
|
22
|
+
},
|
|
23
|
+
JsonSchema: {
|
|
24
|
+
type: CapsulePropertyTypes.Mapping,
|
|
25
|
+
value: '@stream44.studio/t44/caps/JsonSchemas'
|
|
26
|
+
},
|
|
27
|
+
RegisterSchemas: {
|
|
28
|
+
type: CapsulePropertyTypes.StructInit,
|
|
29
|
+
value: async function (this: any): Promise<void> {
|
|
30
|
+
if (this.schema?.schema) {
|
|
31
|
+
const version = this.schemaMinorVersion || '0'
|
|
32
|
+
await this.JsonSchema.registerSchema(this.capsuleName, this.schema.schema, version)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
getFilepath: {
|
|
37
|
+
type: CapsulePropertyTypes.Function,
|
|
38
|
+
value: function (this: any, instanceName: string): string {
|
|
39
|
+
return join(
|
|
40
|
+
this.WorkspaceConfig.workspaceRootDir,
|
|
41
|
+
this.getRelativeFilepath(instanceName)
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
getRelativeFilepath: {
|
|
46
|
+
type: CapsulePropertyTypes.Function,
|
|
47
|
+
value: function (this: any, instanceName: string): string {
|
|
48
|
+
return join(
|
|
49
|
+
'.~o',
|
|
50
|
+
'workspace.foundation',
|
|
51
|
+
capsule['#'].replace(/\//g, '~'),
|
|
52
|
+
this.capsuleName.replace(/\//g, '~'),
|
|
53
|
+
instanceName + '.json'
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
get: {
|
|
58
|
+
type: CapsulePropertyTypes.Function,
|
|
59
|
+
value: async function (this: any, instanceName: string, rawFilepaths?: string[]): Promise<{ data: any; stale: boolean } | null> {
|
|
60
|
+
const factFilepath = this.getFilepath(instanceName)
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const factStat = await stat(factFilepath)
|
|
64
|
+
const factMtime = factStat.mtimeMs
|
|
65
|
+
|
|
66
|
+
// Check if any raw filepaths are newer than our cached fact
|
|
67
|
+
let stale = false
|
|
68
|
+
if (rawFilepaths && rawFilepaths.length > 0) {
|
|
69
|
+
for (const rawPath of rawFilepaths) {
|
|
70
|
+
const fullRawPath = rawPath.startsWith('/')
|
|
71
|
+
? rawPath
|
|
72
|
+
: join(this.WorkspaceConfig.workspaceRootDir, rawPath)
|
|
73
|
+
try {
|
|
74
|
+
const rawStat = await stat(fullRawPath)
|
|
75
|
+
if (rawStat.mtimeMs > factMtime) {
|
|
76
|
+
stale = true
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
// Raw file doesn't exist, consider stale
|
|
81
|
+
stale = true
|
|
82
|
+
break
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const content = await readFile(factFilepath, 'utf-8')
|
|
88
|
+
const parsed = JSON.parse(content)
|
|
89
|
+
const { $schema, $id, _ValidationFeedback, ...data } = parsed
|
|
90
|
+
|
|
91
|
+
return { data, stale }
|
|
92
|
+
} catch {
|
|
93
|
+
return null
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
set: {
|
|
98
|
+
type: CapsulePropertyTypes.Function,
|
|
99
|
+
value: async function (this: any, instanceName: string, data: any): Promise<void> {
|
|
100
|
+
|
|
101
|
+
const factDir = join(
|
|
102
|
+
this.WorkspaceConfig.workspaceRootDir,
|
|
103
|
+
'.~o',
|
|
104
|
+
'workspace.foundation',
|
|
105
|
+
capsule['#'].replace(/\//g, '~'),
|
|
106
|
+
this.capsuleName.replace(/\//g, '~')
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
await mkdir(factDir, { recursive: true })
|
|
110
|
+
|
|
111
|
+
const factFilepath = join(factDir, instanceName + '.json')
|
|
112
|
+
|
|
113
|
+
// Check if schema defines updatedAt or createdAt
|
|
114
|
+
const schemaProperties = this.schema?.schema?.properties || {}
|
|
115
|
+
const hasUpdatedAt = 'updatedAt' in schemaProperties
|
|
116
|
+
const hasCreatedAt = 'createdAt' in schemaProperties
|
|
117
|
+
|
|
118
|
+
// Read existing data to check for changes and preserve timestamps
|
|
119
|
+
let existingData: any = null
|
|
120
|
+
try {
|
|
121
|
+
const existingContent = await readFile(factFilepath, 'utf-8')
|
|
122
|
+
const existingParsed = JSON.parse(existingContent)
|
|
123
|
+
const { $schema, $id, _ValidationFeedback, ...existing } = existingParsed
|
|
124
|
+
existingData = existing
|
|
125
|
+
} catch {
|
|
126
|
+
// File doesn't exist or can't be read
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Prepare output data
|
|
130
|
+
const outputData = { ...data }
|
|
131
|
+
|
|
132
|
+
// Track if we're adding missing timestamps
|
|
133
|
+
let addedCreatedAt = false
|
|
134
|
+
let addedUpdatedAt = false
|
|
135
|
+
|
|
136
|
+
// Set createdAt if schema defines it and it's not set
|
|
137
|
+
if (hasCreatedAt && !outputData.createdAt) {
|
|
138
|
+
if (existingData?.createdAt) {
|
|
139
|
+
// Preserve existing createdAt
|
|
140
|
+
outputData.createdAt = existingData.createdAt
|
|
141
|
+
} else {
|
|
142
|
+
// Set new createdAt (file exists but missing timestamp)
|
|
143
|
+
outputData.createdAt = new Date().toISOString()
|
|
144
|
+
addedCreatedAt = true
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Set updatedAt if schema defines it
|
|
149
|
+
if (hasUpdatedAt) {
|
|
150
|
+
if (!outputData.updatedAt && existingData?.updatedAt) {
|
|
151
|
+
// Preserve existing updatedAt for comparison
|
|
152
|
+
outputData.updatedAt = existingData.updatedAt
|
|
153
|
+
} else if (!outputData.updatedAt) {
|
|
154
|
+
// Set new updatedAt (file exists but missing timestamp, or new file)
|
|
155
|
+
outputData.updatedAt = new Date().toISOString()
|
|
156
|
+
if (existingData) {
|
|
157
|
+
addedUpdatedAt = true
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const version = this.schemaMinorVersion || '0'
|
|
163
|
+
const output: Record<string, any> = {
|
|
164
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
165
|
+
$id: this.capsuleName + '.v' + version,
|
|
166
|
+
...outputData
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Check if content has changed
|
|
170
|
+
if (existingData) {
|
|
171
|
+
const existingOutput = {
|
|
172
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
173
|
+
$id: this.capsuleName + '.v' + version,
|
|
174
|
+
...existingData
|
|
175
|
+
}
|
|
176
|
+
const existingContent = JSON.stringify(existingOutput, null, 4)
|
|
177
|
+
const newContent = JSON.stringify(output, null, 4)
|
|
178
|
+
|
|
179
|
+
if (existingContent === newContent) {
|
|
180
|
+
// Content is identical, skip write
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Content changed - update updatedAt if schema defines it and it matches existing
|
|
185
|
+
// But only if we didn't just add it (which means data actually changed)
|
|
186
|
+
if (hasUpdatedAt && !addedUpdatedAt && !addedCreatedAt && outputData.updatedAt === existingData?.updatedAt) {
|
|
187
|
+
output.updatedAt = new Date().toISOString()
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
await writeFile(factFilepath, JSON.stringify(output, null, 4))
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
delete: {
|
|
195
|
+
type: CapsulePropertyTypes.Function,
|
|
196
|
+
value: async function (this: any, instanceName: string): Promise<void> {
|
|
197
|
+
const { unlink } = await import('fs/promises')
|
|
198
|
+
const factFilepath = this.getFilepath(instanceName)
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
await unlink(factFilepath)
|
|
202
|
+
} catch (error: any) {
|
|
203
|
+
// Ignore if file doesn't exist
|
|
204
|
+
if (error.code !== 'ENOENT') {
|
|
205
|
+
throw error
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}, {
|
|
213
|
+
importMeta: import.meta,
|
|
214
|
+
importStack: makeImportStack(),
|
|
215
|
+
capsuleName: capsule['#'],
|
|
216
|
+
})
|
|
217
|
+
}
|
|
218
|
+
capsule['#'] = '@stream44.studio/t44/caps/WorkspaceEntityFact'
|