@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.
Files changed (99) hide show
  1. package/.dco-signatures +9 -0
  2. package/.github/workflows/dco.yaml +12 -0
  3. package/.github/workflows/gordian-open-integrity.yaml +13 -0
  4. package/.github/workflows/test.yaml +31 -0
  5. package/.o/GordianOpenIntegrity-CurrentLifehash.svg +1026 -0
  6. package/.o/GordianOpenIntegrity-InceptionLifehash.svg +1026 -0
  7. package/.o/GordianOpenIntegrity.yaml +21 -0
  8. package/.o/assets/Hero-Terminal44-v0.jpeg +0 -0
  9. package/.o/stream44.studio/assets/Icon-v1.svg +1170 -0
  10. package/.repo-identifier +1 -0
  11. package/DCO.md +34 -0
  12. package/LICENSE.txt +186 -0
  13. package/README.md +189 -0
  14. package/bin/activate +36 -0
  15. package/bin/activate.ts +30 -0
  16. package/bin/postinstall.sh +19 -0
  17. package/bin/shell +27 -0
  18. package/bin/t44 +27 -0
  19. package/caps/ConfigSchemaStruct.ts +55 -0
  20. package/caps/Home.ts +57 -0
  21. package/caps/HomeRegistry.ts +319 -0
  22. package/caps/HomeRegistryFile.ts +144 -0
  23. package/caps/JsonSchemas.ts +220 -0
  24. package/caps/OpenApiSchema.ts +67 -0
  25. package/caps/PackageDescriptor.ts +88 -0
  26. package/caps/ProjectCatalogs.ts +153 -0
  27. package/caps/ProjectDeployment.ts +426 -0
  28. package/caps/ProjectDevelopment.ts +257 -0
  29. package/caps/ProjectPublishing.ts +654 -0
  30. package/caps/ProjectPulling.ts +234 -0
  31. package/caps/ProjectRack.ts +155 -0
  32. package/caps/ProjectRepository.ts +332 -0
  33. package/caps/ProjectTest.ts +251 -0
  34. package/caps/ProjectTestLib.ts +257 -0
  35. package/caps/RootKey.ts +219 -0
  36. package/caps/SigningKey.ts +243 -0
  37. package/caps/TaskWorkflow.ts +192 -0
  38. package/caps/WorkspaceCli.ts +448 -0
  39. package/caps/WorkspaceConfig.ts +268 -0
  40. package/caps/WorkspaceConfig.yaml +87 -0
  41. package/caps/WorkspaceConfigFile.ts +902 -0
  42. package/caps/WorkspaceConnection.ts +329 -0
  43. package/caps/WorkspaceEntityConfig.ts +78 -0
  44. package/caps/WorkspaceEntityConfig.v0.ts +77 -0
  45. package/caps/WorkspaceEntityFact.ts +218 -0
  46. package/caps/WorkspaceInfo.ts +619 -0
  47. package/caps/WorkspaceInit.ts +30 -0
  48. package/caps/WorkspaceKey.ts +338 -0
  49. package/caps/WorkspaceModel.ts +373 -0
  50. package/caps/WorkspaceProjects.ts +636 -0
  51. package/caps/WorkspacePrompt.ts +430 -0
  52. package/caps/WorkspaceShell.sh +39 -0
  53. package/caps/WorkspaceShell.ts +104 -0
  54. package/caps/WorkspaceShell.yaml +64 -0
  55. package/caps/WorkspaceShellCli.ts +109 -0
  56. package/caps/patterns/README.md +2 -0
  57. package/caps/patterns/git-scm.com/ProjectPublishing.ts +507 -0
  58. package/caps/patterns/semver.org/ProjectPublishing.ts +458 -0
  59. package/docs/Overview.drawio +248 -0
  60. package/docs/Overview.svg +4 -0
  61. package/examples/01-Lifecycle/main.test.ts +223 -0
  62. package/lib/crypto.ts +53 -0
  63. package/lib/key.ts +381 -0
  64. package/lib/schema-console-renderer.ts +181 -0
  65. package/lib/schema-resolver.ts +349 -0
  66. package/lib/ucan.ts +137 -0
  67. package/package.json +91 -0
  68. package/standalone-rt.test.ts +150 -0
  69. package/standalone-rt.ts +140 -0
  70. package/structs/HomeRegistry.ts +55 -0
  71. package/structs/HomeRegistryConfig.ts +60 -0
  72. package/structs/ProjectCatalogsConfig.ts +53 -0
  73. package/structs/ProjectDeploymentConfig.ts +56 -0
  74. package/structs/ProjectDeploymentFact.ts +106 -0
  75. package/structs/ProjectPublishingConfig.ts +78 -0
  76. package/structs/ProjectPublishingFact.ts +68 -0
  77. package/structs/ProjectPullingConfig.ts +52 -0
  78. package/structs/ProjectRack.ts +51 -0
  79. package/structs/ProjectRackConfig.ts +56 -0
  80. package/structs/RepositoryOriginDescriptor.ts +51 -0
  81. package/structs/RootKeyConfig.ts +64 -0
  82. package/structs/SigningKeyConfig.ts +64 -0
  83. package/structs/Workspace.ts +56 -0
  84. package/structs/WorkspaceCatalogs.ts +56 -0
  85. package/structs/WorkspaceCliConfig.ts +53 -0
  86. package/structs/WorkspaceConfig.ts +64 -0
  87. package/structs/WorkspaceConfigFile.ts +50 -0
  88. package/structs/WorkspaceConfigFileMeta.ts +70 -0
  89. package/structs/WorkspaceKey.ts +55 -0
  90. package/structs/WorkspaceKeyConfig.ts +56 -0
  91. package/structs/WorkspaceMappingsConfig.ts +56 -0
  92. package/structs/WorkspaceProject.ts +104 -0
  93. package/structs/WorkspaceProjectsConfig.ts +67 -0
  94. package/structs/WorkspaceShellConfig.ts +83 -0
  95. package/structs/patterns/README.md +2 -0
  96. package/structs/patterns/git-scm.com/ProjectPublishingFact.ts +46 -0
  97. package/tsconfig.json +33 -0
  98. package/workspace-rt.ts +152 -0
  99. package/workspace.yaml +3 -0
@@ -0,0 +1,67 @@
1
+ import { join } from 'node:path'
2
+ import { mkdir, readFile, writeFile } from 'node:fs/promises'
3
+
4
+ export async function capsule({
5
+ encapsulate,
6
+ CapsulePropertyTypes,
7
+ makeImportStack
8
+ }: {
9
+ encapsulate: any
10
+ CapsulePropertyTypes: any
11
+ makeImportStack: any
12
+ }) {
13
+ return encapsulate({
14
+ '#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
15
+ '#@stream44.studio/encapsulate/structs/Capsule': {},
16
+ '#': {
17
+ WorkspaceConfig: {
18
+ type: CapsulePropertyTypes.Mapping,
19
+ value: '@stream44.studio/t44/caps/WorkspaceConfig'
20
+ },
21
+ url: {
22
+ type: CapsulePropertyTypes.Literal,
23
+ value: undefined,
24
+ },
25
+ schemas: {
26
+ type: CapsulePropertyTypes.Literal,
27
+ value: {}
28
+ },
29
+ ensureCached: {
30
+ type: CapsulePropertyTypes.Function,
31
+ value: async function (this: any): Promise<any | null> {
32
+ if (!this.url) return null
33
+
34
+ const cacheDir = join(
35
+ this.WorkspaceConfig.workspaceRootDir,
36
+ '.~o',
37
+ 'workspace.foundation',
38
+ 'OpenApiSchemas',
39
+ )
40
+
41
+ await mkdir(cacheDir, { recursive: true })
42
+
43
+ const schemaFile = join(cacheDir, this.url.replace(/\//g, '~'))
44
+
45
+ try {
46
+ const cached = await readFile(schemaFile, 'utf-8')
47
+ return JSON.parse(cached)
48
+ } catch (error) {
49
+ const response = await fetch(this.url)
50
+ if (!response.ok) {
51
+ return null
52
+ }
53
+ const openApiSpec = await response.json()
54
+ await writeFile(schemaFile, JSON.stringify(openApiSpec, null, 2))
55
+ return openApiSpec
56
+ }
57
+ }
58
+ },
59
+ }
60
+ }
61
+ }, {
62
+ importMeta: import.meta,
63
+ importStack: makeImportStack(),
64
+ capsuleName: capsule['#'],
65
+ })
66
+ }
67
+ capsule['#'] = '@stream44.studio/t44/caps/OpenApiSchema'
@@ -0,0 +1,88 @@
1
+
2
+ import { join } from 'path'
3
+ import { readFile, writeFile } from 'fs/promises'
4
+
5
+ export async function capsule({
6
+ encapsulate,
7
+ CapsulePropertyTypes,
8
+ makeImportStack
9
+ }: {
10
+ encapsulate: any
11
+ CapsulePropertyTypes: any
12
+ makeImportStack: any
13
+ }) {
14
+ return encapsulate({
15
+ '#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
16
+ '#@stream44.studio/encapsulate/structs/Capsule': {},
17
+ '#': {
18
+ JsonSchema: {
19
+ type: CapsulePropertyTypes.Mapping,
20
+ value: '@stream44.studio/t44/caps/JsonSchemas'
21
+ },
22
+ RegisterSchemas: {
23
+ type: CapsulePropertyTypes.StructInit,
24
+ value: async function (this: any): Promise<void> {
25
+ if (this.schema?.schema) {
26
+ const version = this.schemaMinorVersion || '0'
27
+ await this.JsonSchema.registerSchema(this.capsuleName, this.schema.schema, version)
28
+ }
29
+ }
30
+ },
31
+ _readPackageJson: {
32
+ type: CapsulePropertyTypes.Function,
33
+ value: async function (this: any, packageJsonPath: string): Promise<any> {
34
+ const content = await readFile(packageJsonPath, 'utf-8')
35
+ return JSON.parse(content)
36
+ }
37
+ },
38
+ _writePackageJson: {
39
+ type: CapsulePropertyTypes.Function,
40
+ value: async function (this: any, packageJsonPath: string, pkg: any): Promise<void> {
41
+ await writeFile(packageJsonPath, JSON.stringify(pkg, null, 4) + '\n')
42
+ }
43
+ },
44
+ _resolveConfigSection: {
45
+ type: CapsulePropertyTypes.Function,
46
+ value: function (this: any, pkg: any): any {
47
+ const structKey = this.capsuleName
48
+ if (!pkg.config) return undefined
49
+ if (!pkg.config.o) return undefined
50
+ if (!pkg.config.o['workspace.foundation']) return undefined
51
+ return pkg.config.o['workspace.foundation'][structKey] || undefined
52
+ }
53
+ },
54
+ get: {
55
+ type: CapsulePropertyTypes.Function,
56
+ value: async function (this: any, packageJsonPath: string): Promise<any | null> {
57
+ try {
58
+ const pkg = await this._readPackageJson(packageJsonPath)
59
+ return this._resolveConfigSection(pkg) || null
60
+ } catch {
61
+ return null
62
+ }
63
+ }
64
+ },
65
+ set: {
66
+ type: CapsulePropertyTypes.Function,
67
+ value: async function (this: any, packageJsonPath: string, data: any): Promise<void> {
68
+ const pkg = await this._readPackageJson(packageJsonPath)
69
+ const structKey = this.capsuleName
70
+
71
+ if (!pkg.config) pkg.config = {}
72
+ if (!pkg.config.o) pkg.config.o = {}
73
+ if (!pkg.config.o['workspace.foundation']) pkg.config.o['workspace.foundation'] = {}
74
+
75
+ pkg.config.o['workspace.foundation'][structKey] = data
76
+
77
+ await this._writePackageJson(packageJsonPath, pkg)
78
+ }
79
+ },
80
+ }
81
+ }
82
+ }, {
83
+ importMeta: import.meta,
84
+ importStack: makeImportStack(),
85
+ capsuleName: capsule['#'],
86
+ })
87
+ }
88
+ capsule['#'] = '@stream44.studio/t44/caps/PackageDescriptor'
@@ -0,0 +1,153 @@
1
+
2
+ export async function capsule({
3
+ encapsulate,
4
+ CapsulePropertyTypes,
5
+ makeImportStack
6
+ }: {
7
+ encapsulate: any
8
+ CapsulePropertyTypes: any
9
+ makeImportStack: any
10
+ }) {
11
+ return encapsulate({
12
+ '#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
13
+ '#@stream44.studio/encapsulate/structs/Capsule': {},
14
+ '#@stream44.studio/t44/structs/ProjectCatalogsConfig': {
15
+ as: '$ProjectCatalogsConfig',
16
+ },
17
+ '#': {
18
+ HomeRegistry: {
19
+ type: CapsulePropertyTypes.Mapping,
20
+ value: '@stream44.studio/t44/caps/HomeRegistry'
21
+ },
22
+ list: {
23
+ type: CapsulePropertyTypes.GetterFunction,
24
+ value: async function (this: any): Promise<Record<string, any>> {
25
+ const catalogsConfig = await this.$ProjectCatalogsConfig.config
26
+ return catalogsConfig?.catalogs || {}
27
+ }
28
+ },
29
+ validate: {
30
+ type: CapsulePropertyTypes.Function,
31
+ value: async function (this: any): Promise<boolean> {
32
+ const catalogsConfig = await this.$ProjectCatalogsConfig.config
33
+ const catalogs = catalogsConfig?.catalogs
34
+
35
+ if (!catalogs || typeof catalogs !== 'object') {
36
+ return true
37
+ }
38
+
39
+ const chalk = (await import('chalk')).default
40
+
41
+ for (const [catalogName, catalogConfig] of Object.entries(catalogs)) {
42
+ if (!catalogConfig || typeof catalogConfig !== 'object') {
43
+ console.log(chalk.red(`\nāœ— Invalid catalog '${catalogName}': must be an object.\n`))
44
+ return false
45
+ }
46
+
47
+ const fileName = catalogName.replace(/\//g, '~')
48
+ const typedConfig = catalogConfig as Record<string, any>
49
+
50
+ const existing = await this.HomeRegistry.getCatalog(fileName) || {}
51
+ const now = new Date().toISOString()
52
+
53
+ // Deep merge: config keys into existing, preserving existing nested data
54
+ let changed = false
55
+ for (const [key, value] of Object.entries(typedConfig)) {
56
+ if (key === 'repositories' && typeof value === 'object' && typeof existing[key] === 'object') {
57
+ // Merge repositories: add missing repos, keep existing repo data
58
+ for (const [repoName, repoConfig] of Object.entries(value as Record<string, any>)) {
59
+ if (!existing[key][repoName]) {
60
+ existing[key][repoName] = repoConfig || {}
61
+ changed = true
62
+ }
63
+ }
64
+ } else if (JSON.stringify(existing[key]) !== JSON.stringify(value)) {
65
+ existing[key] = value
66
+ changed = true
67
+ }
68
+ }
69
+
70
+ if (changed) {
71
+ existing.updatedAt = now
72
+ }
73
+ if (!existing.createdAt) {
74
+ existing.createdAt = now
75
+ }
76
+
77
+ const filePath = await this.HomeRegistry.setCatalog(fileName, existing)
78
+ if (changed) {
79
+ console.log(chalk.green(` āœ“ Catalog '${catalogName}' → ${filePath}`))
80
+ }
81
+ }
82
+
83
+ return true
84
+ }
85
+ },
86
+ updateCatalogRepository: {
87
+ type: CapsulePropertyTypes.Function,
88
+ value: async function (this: any, {
89
+ repoName,
90
+ providerKey,
91
+ providerData,
92
+ }: {
93
+ repoName: string
94
+ providerKey: string
95
+ providerData: Record<string, any>
96
+ }): Promise<void> {
97
+ const catalogsConfig = await this.$ProjectCatalogsConfig.config
98
+ const catalogs = catalogsConfig?.catalogs
99
+
100
+ if (!catalogs || typeof catalogs !== 'object') return
101
+
102
+ for (const [catalogName, catalogConfig] of Object.entries(catalogs)) {
103
+ const typedConfig = catalogConfig as Record<string, any>
104
+ const repositories = typedConfig.repositories
105
+ if (!repositories || typeof repositories !== 'object') continue
106
+ if (!(repoName in repositories)) continue
107
+
108
+ const fileName = catalogName.replace(/\//g, '~')
109
+ const existing = await this.HomeRegistry.getCatalog(fileName)
110
+ if (!existing) continue
111
+
112
+ if (!existing.repositories) existing.repositories = {}
113
+ if (!existing.repositories[repoName]) existing.repositories[repoName] = {}
114
+ const repoEntry = existing.repositories[repoName]
115
+ const now = new Date().toISOString()
116
+
117
+ const existingEntity = repoEntry[providerKey]
118
+ const entityCreatedAt = existingEntity?.createdAt || now
119
+
120
+ // Check if data actually changed (compare without timestamps, order-independent)
121
+ const { createdAt: _ec, updatedAt: _eu, ...existingData } = existingEntity || {}
122
+ const stableStringify = (obj: any): string => JSON.stringify(obj, (_, v) =>
123
+ v && typeof v === 'object' && !Array.isArray(v)
124
+ ? Object.keys(v).sort().reduce((o: any, k) => { o[k] = v[k]; return o }, {})
125
+ : v
126
+ )
127
+ const dataChanged = stableStringify(existingData) !== stableStringify(providerData)
128
+
129
+ repoEntry[providerKey] = {
130
+ ...providerData,
131
+ createdAt: entityCreatedAt,
132
+ updatedAt: dataChanged ? now : (existingEntity?.updatedAt || now),
133
+ }
134
+
135
+ if (!repoEntry.createdAt) repoEntry.createdAt = now
136
+ if (dataChanged) {
137
+ repoEntry.updatedAt = now
138
+ existing.updatedAt = now
139
+ }
140
+
141
+ await this.HomeRegistry.setCatalog(fileName, existing)
142
+ }
143
+ }
144
+ },
145
+ }
146
+ }
147
+ }, {
148
+ importMeta: import.meta,
149
+ importStack: makeImportStack(),
150
+ capsuleName: capsule['#'],
151
+ })
152
+ }
153
+ capsule['#'] = '@stream44.studio/t44/caps/ProjectCatalogs'