t44 0.4.0-rc.3
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.yml +12 -0
- package/.o/GordianOpenIntegrity-CurrentLifehash.svg +1026 -0
- package/.o/GordianOpenIntegrity-InceptionLifehash.svg +1026 -0
- package/.o/GordianOpenIntegrity.yaml +25 -0
- package/.o/assets/Hero-Terminal44-v0.jpeg +0 -0
- package/DCO.md +34 -0
- package/LICENSE.md +203 -0
- package/README.md +183 -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 +51 -0
- package/caps/HomeRegistry.ts +313 -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 +363 -0
- package/caps/ProjectDevelopment.ts +257 -0
- package/caps/ProjectPublishing.ts +522 -0
- package/caps/ProjectRack.ts +155 -0
- package/caps/ProjectRepository.ts +322 -0
- package/caps/RootKey.ts +219 -0
- package/caps/SigningKey.ts +243 -0
- package/caps/WorkspaceCli.ts +442 -0
- package/caps/WorkspaceConfig.ts +268 -0
- package/caps/WorkspaceConfig.yaml +71 -0
- package/caps/WorkspaceConfigFile.ts +799 -0
- package/caps/WorkspaceConnection.ts +249 -0
- package/caps/WorkspaceEntityConfig.ts +78 -0
- package/caps/WorkspaceEntityConfig.v0.ts +77 -0
- package/caps/WorkspaceEntityFact.ts +218 -0
- package/caps/WorkspaceInfo.ts +595 -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 +406 -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/WorkspaceTest.ts +167 -0
- package/caps/providers/README.md +2 -0
- package/caps/providers/bunny.net/ProjectDeployment.ts +327 -0
- package/caps/providers/bunny.net/api-pull.test.ts +319 -0
- package/caps/providers/bunny.net/api-pull.ts +164 -0
- package/caps/providers/bunny.net/api-storage.test.ts +168 -0
- package/caps/providers/bunny.net/api-storage.ts +248 -0
- package/caps/providers/bunny.net/api.ts +95 -0
- package/caps/providers/dynadot.com/ProjectDeployment.ts +202 -0
- package/caps/providers/dynadot.com/api-domains.test.ts +224 -0
- package/caps/providers/dynadot.com/api-domains.ts +169 -0
- package/caps/providers/dynadot.com/api-restful-v1.test.ts +190 -0
- package/caps/providers/dynadot.com/api-restful-v1.ts +94 -0
- package/caps/providers/dynadot.com/api-restful-v2.test.ts +200 -0
- package/caps/providers/dynadot.com/api-restful-v2.ts +94 -0
- package/caps/providers/git-scm.com/ProjectPublishing.ts +654 -0
- package/caps/providers/github.com/ProjectPublishing.ts +118 -0
- package/caps/providers/github.com/api.ts +115 -0
- package/caps/providers/npmjs.com/ProjectPublishing.ts +536 -0
- package/caps/providers/semver.org/ProjectPublishing.ts +286 -0
- package/caps/providers/vercel.com/ProjectDeployment.ts +326 -0
- package/caps/providers/vercel.com/api.test.ts +67 -0
- package/caps/providers/vercel.com/api.ts +132 -0
- package/caps/providers/vercel.com/bun.lock +194 -0
- package/caps/providers/vercel.com/package.json +10 -0
- package/caps/providers/vercel.com/project.test.ts +108 -0
- package/caps/providers/vercel.com/project.ts +150 -0
- package/caps/providers/vercel.com/tsconfig.json +28 -0
- package/docs/Overview.drawio +248 -0
- package/docs/Overview.svg +4 -0
- package/lib/crypto.ts +53 -0
- package/lib/key.ts +365 -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 +101 -0
- package/structs/HomeRegistry.ts +55 -0
- package/structs/HomeRegistryConfig.ts +56 -0
- package/structs/ProjectCatalogsConfig.ts +53 -0
- package/structs/ProjectDeploymentConfig.ts +56 -0
- package/structs/ProjectDeploymentFact.ts +106 -0
- package/structs/ProjectPublishingFact.ts +68 -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/WorkspacePublishingConfig.ts +65 -0
- package/structs/WorkspaceShellConfig.ts +83 -0
- package/structs/providers/README.md +2 -0
- package/structs/providers/bunny.net/PullZoneFact.ts +55 -0
- package/structs/providers/bunny.net/PullZoneListFact.ts +55 -0
- package/structs/providers/bunny.net/StorageZoneFact.ts +55 -0
- package/structs/providers/bunny.net/StorageZoneListFact.ts +55 -0
- package/structs/providers/bunny.net/WorkspaceConnectionConfig.ts +43 -0
- package/structs/providers/dynadot.com/DomainFact.ts +46 -0
- package/structs/providers/dynadot.com/WorkspaceConnectionConfig.ts +54 -0
- package/structs/providers/git-scm.com/ProjectPublishingFact.ts +46 -0
- package/structs/providers/github.com/ProjectPublishingFact.ts +46 -0
- package/structs/providers/github.com/WorkspaceConnectionConfig.ts +43 -0
- package/structs/providers/npmjs.com/ProjectPublishingFact.ts +46 -0
- package/structs/providers/vercel.com/ProjectDeploymentFact.ts +55 -0
- package/structs/providers/vercel.com/WorkspaceConnectionConfig.ts +49 -0
- package/tests/01-Lifecycle/main.test.ts +173 -0
- package/tsconfig.json +28 -0
- package/workspace-rt.ts +134 -0
- package/workspace.yaml +3 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#t44/caps/ConfigSchemaStruct': {
|
|
10
|
+
as: 'schema',
|
|
11
|
+
options: {
|
|
12
|
+
'#': {
|
|
13
|
+
schema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
createdAt: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
format: 'date-time',
|
|
19
|
+
description: 'ISO 8601 timestamp when the project publishing fact was created'
|
|
20
|
+
},
|
|
21
|
+
updatedAt: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
format: 'date-time',
|
|
24
|
+
description: 'ISO 8601 timestamp when the project publishing fact was last updated'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
additionalProperties: true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
'#': {
|
|
33
|
+
capsuleName: {
|
|
34
|
+
type: CapsulePropertyTypes.Literal,
|
|
35
|
+
value: capsule['#']
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, {
|
|
40
|
+
extendsCapsule: 't44/caps/WorkspaceEntityFact',
|
|
41
|
+
importMeta: import.meta,
|
|
42
|
+
importStack: makeImportStack(),
|
|
43
|
+
capsuleName: capsule['#'],
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
capsule['#'] = 't44/structs/providers/github.com/ProjectPublishingFact'
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#t44/caps/ConfigSchemaStruct': {
|
|
10
|
+
as: 'schema',
|
|
11
|
+
options: {
|
|
12
|
+
'#': {
|
|
13
|
+
schema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
apiToken: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
title: 'GitHub Personal Access Token',
|
|
19
|
+
description: 'Your GitHub personal access token from https://github.com/settings/tokens (needs repo scope)',
|
|
20
|
+
minLength: 10,
|
|
21
|
+
pattern: '^(ghp_[A-Za-z0-9]+|github_pat_[A-Za-z0-9_]+)$'
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
required: ['apiToken']
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
'#': {
|
|
30
|
+
capsuleName: {
|
|
31
|
+
type: CapsulePropertyTypes.Literal,
|
|
32
|
+
value: capsule['#']
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}, {
|
|
37
|
+
extendsCapsule: 't44/caps/WorkspaceConnection',
|
|
38
|
+
importMeta: import.meta,
|
|
39
|
+
importStack: makeImportStack(),
|
|
40
|
+
capsuleName: capsule['#'],
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
capsule['#'] = 't44/structs/providers/github.com/WorkspaceConnectionConfig'
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#t44/caps/ConfigSchemaStruct': {
|
|
10
|
+
as: 'schema',
|
|
11
|
+
options: {
|
|
12
|
+
'#': {
|
|
13
|
+
schema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
createdAt: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
format: 'date-time',
|
|
19
|
+
description: 'ISO 8601 timestamp when the project publishing fact was created'
|
|
20
|
+
},
|
|
21
|
+
updatedAt: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
format: 'date-time',
|
|
24
|
+
description: 'ISO 8601 timestamp when the project publishing fact was last updated'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
additionalProperties: true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
'#': {
|
|
33
|
+
capsuleName: {
|
|
34
|
+
type: CapsulePropertyTypes.Literal,
|
|
35
|
+
value: capsule['#']
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, {
|
|
40
|
+
extendsCapsule: 't44/caps/WorkspaceEntityFact',
|
|
41
|
+
importMeta: import.meta,
|
|
42
|
+
importStack: makeImportStack(),
|
|
43
|
+
capsuleName: capsule['#'],
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
capsule['#'] = 't44/structs/providers/npmjs.com/ProjectPublishingFact'
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#t44/caps/ConfigSchemaStruct': {
|
|
10
|
+
as: 'schema',
|
|
11
|
+
options: {
|
|
12
|
+
'#': {
|
|
13
|
+
schema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
createdAt: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
format: 'date-time',
|
|
19
|
+
description: 'ISO 8601 timestamp when the project deployment fact was created'
|
|
20
|
+
},
|
|
21
|
+
updatedAt: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
format: 'date-time',
|
|
24
|
+
description: 'ISO 8601 timestamp when the project deployment fact was last updated'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
additionalProperties: true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
'#t44/caps/OpenApiSchema': {
|
|
33
|
+
as: 'schemaOpenApi',
|
|
34
|
+
options: {
|
|
35
|
+
'#': {
|
|
36
|
+
url: 'https://openapi.vercel.sh/',
|
|
37
|
+
def: '#/paths/~1v9~1projects~1{idOrName}/get/responses/200/content/application~1json/schema'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
'#': {
|
|
42
|
+
capsuleName: {
|
|
43
|
+
type: CapsulePropertyTypes.Literal,
|
|
44
|
+
value: capsule['#']
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}, {
|
|
49
|
+
extendsCapsule: 't44/caps/WorkspaceEntityFact',
|
|
50
|
+
importMeta: import.meta,
|
|
51
|
+
importStack: makeImportStack(),
|
|
52
|
+
capsuleName: capsule['#'],
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
capsule['#'] = 't44/structs/providers/vercel.com/ProjectDeploymentFact'
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
|
|
2
|
+
export async function capsule({
|
|
3
|
+
encapsulate,
|
|
4
|
+
CapsulePropertyTypes,
|
|
5
|
+
makeImportStack
|
|
6
|
+
}: any) {
|
|
7
|
+
return encapsulate({
|
|
8
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
9
|
+
'#t44/caps/ConfigSchemaStruct': {
|
|
10
|
+
as: 'schema',
|
|
11
|
+
options: {
|
|
12
|
+
'#': {
|
|
13
|
+
schema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
apiToken: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
title: 'Vercel API Token',
|
|
19
|
+
description: 'Your Vercel API token from https://vercel.com/account/tokens',
|
|
20
|
+
minLength: 20,
|
|
21
|
+
pattern: '^[A-Za-z0-9_-]+$'
|
|
22
|
+
},
|
|
23
|
+
team: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
title: 'Default Team',
|
|
26
|
+
description: 'Your default Vercel team slug',
|
|
27
|
+
minLength: 1
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
required: ['apiToken']
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
'#': {
|
|
36
|
+
capsuleName: {
|
|
37
|
+
type: CapsulePropertyTypes.Literal,
|
|
38
|
+
value: capsule['#']
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}, {
|
|
43
|
+
extendsCapsule: 't44/caps/WorkspaceConnection',
|
|
44
|
+
importMeta: import.meta,
|
|
45
|
+
importStack: makeImportStack(),
|
|
46
|
+
capsuleName: capsule['#'],
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
capsule['#'] = 't44/structs/providers/vercel.com/WorkspaceConnectionConfig'
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env bun test
|
|
2
|
+
// Set VERBOSE=1 to see stdout/stderr from spawned t44 commands
|
|
3
|
+
|
|
4
|
+
export const testConfig = {
|
|
5
|
+
group: 'lifecycle',
|
|
6
|
+
runOnAll: false,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
import { join } from 'path'
|
|
10
|
+
import { mkdir, writeFile, rm, stat } from 'fs/promises'
|
|
11
|
+
import * as bunTest from 'bun:test'
|
|
12
|
+
import { run } from 't44/workspace-rt'
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
test: { describe, it, expect, beforeAll },
|
|
16
|
+
} = await run(async ({ encapsulate, CapsulePropertyTypes, makeImportStack }: any) => {
|
|
17
|
+
const spine = await encapsulate({
|
|
18
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
19
|
+
'#@stream44.studio/encapsulate/structs/Capsule': {},
|
|
20
|
+
'#': {
|
|
21
|
+
test: {
|
|
22
|
+
type: CapsulePropertyTypes.Mapping,
|
|
23
|
+
value: 't44/caps/WorkspaceTest',
|
|
24
|
+
options: {
|
|
25
|
+
'#': {
|
|
26
|
+
bunTest,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}, {
|
|
33
|
+
importMeta: import.meta,
|
|
34
|
+
importStack: makeImportStack(),
|
|
35
|
+
capsuleName: 't44/tests/01-Lifecycle/main.test'
|
|
36
|
+
})
|
|
37
|
+
return { spine }
|
|
38
|
+
}, async ({ spine, apis }: any) => {
|
|
39
|
+
return apis[spine.capsuleSourceLineRef]
|
|
40
|
+
}, {
|
|
41
|
+
importMeta: import.meta
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const testDir = join(import.meta.dir, '.~main.test')
|
|
45
|
+
const t44Bin = join(import.meta.dir, '../../bin/t44')
|
|
46
|
+
|
|
47
|
+
const homeDir = join(testDir, 'lifecycle', 'home')
|
|
48
|
+
const repoDir = join(testDir, 'lifecycle', 'repo')
|
|
49
|
+
const env = { ...process.env, T44_HOME_DIR: homeDir, T44_KEYS_PASSPHRASE: 't44-test' }
|
|
50
|
+
|
|
51
|
+
async function runT44(...args: string[]) {
|
|
52
|
+
const proc = Bun.spawn([t44Bin, ...args, '--yes'], {
|
|
53
|
+
env,
|
|
54
|
+
cwd: repoDir,
|
|
55
|
+
stdout: 'pipe',
|
|
56
|
+
stderr: 'pipe',
|
|
57
|
+
stdin: 'pipe',
|
|
58
|
+
})
|
|
59
|
+
proc.stdin.end()
|
|
60
|
+
|
|
61
|
+
const timeout = setTimeout(() => proc.kill(), 15_000)
|
|
62
|
+
|
|
63
|
+
const stdoutChunks: string[] = []
|
|
64
|
+
const stderrChunks: string[] = []
|
|
65
|
+
|
|
66
|
+
const verbose = !!process.env.VERBOSE
|
|
67
|
+
|
|
68
|
+
const stdoutReader = new WritableStream({
|
|
69
|
+
write(chunk) {
|
|
70
|
+
const text = new TextDecoder().decode(chunk)
|
|
71
|
+
stdoutChunks.push(text)
|
|
72
|
+
if (verbose) process.stdout.write(text)
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const stderrReader = new WritableStream({
|
|
77
|
+
write(chunk) {
|
|
78
|
+
const text = new TextDecoder().decode(chunk)
|
|
79
|
+
stderrChunks.push(text)
|
|
80
|
+
if (verbose) process.stderr.write(text)
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const [exitCode] = await Promise.all([
|
|
85
|
+
proc.exited,
|
|
86
|
+
proc.stdout.pipeTo(stdoutReader),
|
|
87
|
+
proc.stderr.pipeTo(stderrReader),
|
|
88
|
+
])
|
|
89
|
+
|
|
90
|
+
clearTimeout(timeout)
|
|
91
|
+
|
|
92
|
+
return { exitCode, stdout: stdoutChunks.join(''), stderr: stderrChunks.join('') }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
describe('t44 lifecycle', function () {
|
|
96
|
+
|
|
97
|
+
beforeAll(async () => {
|
|
98
|
+
await rm(join(testDir, 'lifecycle'), { recursive: true, force: true })
|
|
99
|
+
await mkdir(homeDir, { recursive: true })
|
|
100
|
+
await mkdir(join(homeDir, '.ssh'), { recursive: true })
|
|
101
|
+
await mkdir(join(repoDir, '.workspace'), { recursive: true })
|
|
102
|
+
|
|
103
|
+
const workspaceYaml = `extends:
|
|
104
|
+
- 't44/workspace.yaml'
|
|
105
|
+
`
|
|
106
|
+
await writeFile(join(repoDir, '.workspace', 'workspace.yaml'), workspaceYaml)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('init — t44 info --yes initializes workspace', async () => {
|
|
110
|
+
const { exitCode, stdout, stderr } = await runT44('info')
|
|
111
|
+
|
|
112
|
+
if (exitCode !== 0) {
|
|
113
|
+
console.log('STDOUT:', stdout)
|
|
114
|
+
console.log('STDERR:', stderr)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
expect(exitCode).toBe(0)
|
|
118
|
+
|
|
119
|
+
// Verify registry was created
|
|
120
|
+
const registryDir = join(homeDir, '.o/workspace.foundation')
|
|
121
|
+
const registryStat = await stat(registryDir)
|
|
122
|
+
expect(registryStat.isDirectory()).toBe(true)
|
|
123
|
+
|
|
124
|
+
// Verify SSH keys were created
|
|
125
|
+
const sshDir = join(homeDir, '.ssh')
|
|
126
|
+
const rootKeyStat = await stat(join(sshDir, 'id_t44_ed25519'))
|
|
127
|
+
expect(rootKeyStat.isFile()).toBe(true)
|
|
128
|
+
|
|
129
|
+
const signingKeyStat = await stat(join(sshDir, 'id_t44_signing_ed25519'))
|
|
130
|
+
expect(signingKeyStat.isFile()).toBe(true)
|
|
131
|
+
}, 15_000)
|
|
132
|
+
|
|
133
|
+
it('info — displays workspace information', async () => {
|
|
134
|
+
const { exitCode, stdout, stderr } = await runT44('info', '--full')
|
|
135
|
+
|
|
136
|
+
if (exitCode !== 0) {
|
|
137
|
+
console.log('STDOUT:', stdout)
|
|
138
|
+
console.log('STDERR:', stderr)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
expect(exitCode).toBe(0)
|
|
142
|
+
expect(stdout).toContain('WORKSPACE INFORMATION')
|
|
143
|
+
expect(stdout).toContain('repo')
|
|
144
|
+
expect(stdout).toContain('did:key:')
|
|
145
|
+
expect(stdout).toContain('CONFIGURATION FILES')
|
|
146
|
+
}, 15_000)
|
|
147
|
+
|
|
148
|
+
it('activate — outputs shell export statements', async () => {
|
|
149
|
+
const { exitCode, stdout, stderr } = await runT44('activate')
|
|
150
|
+
|
|
151
|
+
if (exitCode !== 0) {
|
|
152
|
+
console.log('STDOUT:', stdout)
|
|
153
|
+
console.log('STDERR:', stderr)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
expect(exitCode).toBe(0)
|
|
157
|
+
expect(stdout).toContain('export ')
|
|
158
|
+
expect(stdout).toContain('F_WORKSPACE_DIR')
|
|
159
|
+
}, 15_000)
|
|
160
|
+
|
|
161
|
+
it('query — displays workspace model', async () => {
|
|
162
|
+
const { exitCode, stdout, stderr } = await runT44('query', '--full')
|
|
163
|
+
|
|
164
|
+
if (exitCode !== 0) {
|
|
165
|
+
console.log('STDOUT:', stdout)
|
|
166
|
+
console.log('STDERR:', stderr)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
expect(exitCode).toBe(0)
|
|
170
|
+
expect(stdout).toContain('WorkspaceConfig')
|
|
171
|
+
}, 15_000)
|
|
172
|
+
|
|
173
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.paths.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "es2021",
|
|
5
|
+
"module": "esnext",
|
|
6
|
+
"lib": [
|
|
7
|
+
"ES2021",
|
|
8
|
+
"DOM"
|
|
9
|
+
],
|
|
10
|
+
"types": [
|
|
11
|
+
"bun",
|
|
12
|
+
"node"
|
|
13
|
+
],
|
|
14
|
+
"moduleResolution": "bundler",
|
|
15
|
+
"strict": true,
|
|
16
|
+
"esModuleInterop": true,
|
|
17
|
+
"skipLibCheck": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"resolveJsonModule": true,
|
|
20
|
+
"allowSyntheticDefaultImports": true
|
|
21
|
+
},
|
|
22
|
+
"include": [
|
|
23
|
+
"**/*.ts"
|
|
24
|
+
],
|
|
25
|
+
"exclude": [
|
|
26
|
+
"node_modules"
|
|
27
|
+
]
|
|
28
|
+
}
|
package/workspace-rt.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/// <reference types="bun" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
|
|
5
|
+
const startTime = Date.now()
|
|
6
|
+
|
|
7
|
+
import { join, resolve } from 'path'
|
|
8
|
+
import { access } from 'fs/promises'
|
|
9
|
+
import chalk from 'chalk'
|
|
10
|
+
import { CapsuleSpineFactory } from "@stream44.studio/encapsulate/spine-factories/CapsuleSpineFactory.v0"
|
|
11
|
+
import { CapsuleSpineContract } from "@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0/Membrane.v0"
|
|
12
|
+
import { TimingObserver } from "@stream44.studio/encapsulate/spine-factories/TimingObserver"
|
|
13
|
+
|
|
14
|
+
async function findWorkspaceRoot(): Promise<string> {
|
|
15
|
+
let currentDir = resolve(process.cwd())
|
|
16
|
+
|
|
17
|
+
while (true) {
|
|
18
|
+
const workspaceConfigPath = join(currentDir, '.workspace', 'workspace.yaml')
|
|
19
|
+
try {
|
|
20
|
+
await access(workspaceConfigPath)
|
|
21
|
+
return currentDir
|
|
22
|
+
} catch {
|
|
23
|
+
// File doesn't exist, continue traversing
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const parentDir = resolve(currentDir, '..')
|
|
27
|
+
if (parentDir === currentDir) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Could not find workspace root. Please run this command from within a workspace directory ` +
|
|
30
|
+
`(a directory containing .workspace/workspace.yaml).`
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
currentDir = parentDir
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function run(encapsulateHandler: any, runHandler: any, options?: { importMeta?: { dir: string } }) {
|
|
38
|
+
|
|
39
|
+
const timing = process.argv.includes('--trace') ? TimingObserver({ startTime }) : undefined
|
|
40
|
+
|
|
41
|
+
timing?.recordMajor('INIT SPINE')
|
|
42
|
+
|
|
43
|
+
const eventsByKey = new Map<string, any>()
|
|
44
|
+
|
|
45
|
+
const workspaceRootDir = await findWorkspaceRoot()
|
|
46
|
+
|
|
47
|
+
const { encapsulate, freeze, CapsulePropertyTypes, makeImportStack, hoistSnapshot } = await CapsuleSpineFactory({
|
|
48
|
+
spineFilesystemRoot: workspaceRootDir,
|
|
49
|
+
capsuleModuleProjectionRoot: (import.meta as any).dir,
|
|
50
|
+
enableCallerStackInference: true,
|
|
51
|
+
spineContracts: {
|
|
52
|
+
['#' + CapsuleSpineContract['#']]: CapsuleSpineContract
|
|
53
|
+
},
|
|
54
|
+
timing,
|
|
55
|
+
onMembraneEvent: timing ? (event: any) => {
|
|
56
|
+
const instanceId = event.target?.spineContractCapsuleInstanceId
|
|
57
|
+
const eventIndex = event.eventIndex
|
|
58
|
+
|
|
59
|
+
// Store event by composite key (instance ID + event index)
|
|
60
|
+
const key = `${eventIndex}`
|
|
61
|
+
eventsByKey.set(key, event)
|
|
62
|
+
|
|
63
|
+
let capsuleRef = event.target?.capsuleSourceLineRef
|
|
64
|
+
let prop = event.target?.prop
|
|
65
|
+
let callerLocation = event.caller ? `${event.caller.filepath}:${event.caller.line}` : 'unknown'
|
|
66
|
+
const eventType = event.event
|
|
67
|
+
|
|
68
|
+
// For call-result events, look up the original call event to get all info
|
|
69
|
+
if (eventType === 'call-result') {
|
|
70
|
+
const callKey = `${event.callEventIndex}`
|
|
71
|
+
const callEvent = eventsByKey.get(callKey)
|
|
72
|
+
if (callEvent) {
|
|
73
|
+
capsuleRef = callEvent.target?.capsuleSourceLineRef || capsuleRef
|
|
74
|
+
prop = callEvent.target?.prop || prop
|
|
75
|
+
if (callEvent.caller) {
|
|
76
|
+
callerLocation = `${callEvent.caller.filepath}:${callEvent.caller.line}`
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.error(
|
|
82
|
+
chalk.gray(`[${eventIndex}]`),
|
|
83
|
+
chalk.cyan(eventType.padEnd(12)),
|
|
84
|
+
chalk.yellow(capsuleRef),
|
|
85
|
+
chalk.magenta(`.${prop}`),
|
|
86
|
+
chalk.dim(`from ${callerLocation}`)
|
|
87
|
+
)
|
|
88
|
+
} : undefined
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
timing?.recordMajor('ENCAPSULATE')
|
|
92
|
+
|
|
93
|
+
const exportedApi = await encapsulateHandler({
|
|
94
|
+
encapsulate,
|
|
95
|
+
CapsulePropertyTypes,
|
|
96
|
+
makeImportStack
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
timing?.recordMajor('FREEZE')
|
|
100
|
+
|
|
101
|
+
const snapshot = await freeze()
|
|
102
|
+
|
|
103
|
+
timing?.recordMajor('HOIST SNAPSHOT')
|
|
104
|
+
|
|
105
|
+
const { run } = await hoistSnapshot({
|
|
106
|
+
snapshot
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
timing?.recordMajor('RUN')
|
|
110
|
+
|
|
111
|
+
const result = await run({
|
|
112
|
+
overrides: {
|
|
113
|
+
['t44/caps/WorkspaceConfig']: {
|
|
114
|
+
'#': {
|
|
115
|
+
workspaceRootDir
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
['t44/caps/WorkspaceTest']: {
|
|
119
|
+
'#': {
|
|
120
|
+
testRootDir: options?.importMeta?.dir
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}, async (opts) => {
|
|
125
|
+
return runHandler({
|
|
126
|
+
...opts,
|
|
127
|
+
...(exportedApi || {})
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
timing?.recordMajor('DONE')
|
|
132
|
+
|
|
133
|
+
return result
|
|
134
|
+
}
|
package/workspace.yaml
ADDED