@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,243 @@
|
|
|
1
|
+
export async function capsule({
|
|
2
|
+
encapsulate,
|
|
3
|
+
CapsulePropertyTypes,
|
|
4
|
+
makeImportStack
|
|
5
|
+
}: {
|
|
6
|
+
encapsulate: any
|
|
7
|
+
CapsulePropertyTypes: any
|
|
8
|
+
makeImportStack: any
|
|
9
|
+
}) {
|
|
10
|
+
return encapsulate({
|
|
11
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
12
|
+
'#@stream44.studio/encapsulate/structs/Capsule': {},
|
|
13
|
+
'#@stream44.studio/t44/structs/WorkspaceConfig': {
|
|
14
|
+
as: '$WorkspaceConfig'
|
|
15
|
+
},
|
|
16
|
+
'#@stream44.studio/t44/structs/SigningKeyConfig': {
|
|
17
|
+
as: '$SigningKeyConfig'
|
|
18
|
+
},
|
|
19
|
+
'#': {
|
|
20
|
+
Home: {
|
|
21
|
+
type: CapsulePropertyTypes.Mapping,
|
|
22
|
+
value: '@stream44.studio/t44/caps/Home'
|
|
23
|
+
},
|
|
24
|
+
WorkspacePrompt: {
|
|
25
|
+
type: CapsulePropertyTypes.Mapping,
|
|
26
|
+
value: '@stream44.studio/t44/caps/WorkspacePrompt'
|
|
27
|
+
},
|
|
28
|
+
ensureKey: {
|
|
29
|
+
type: CapsulePropertyTypes.Function,
|
|
30
|
+
value: async function (this: any): Promise<{ keyName: string; privateKeyPath: string; publicKey: string; keyFingerprint: string } | null> {
|
|
31
|
+
const { join } = await import('path')
|
|
32
|
+
const { readFile, stat: statFile } = await import('fs/promises')
|
|
33
|
+
const chalk = (await import('chalk')).default
|
|
34
|
+
const {
|
|
35
|
+
discoverEd25519Keys,
|
|
36
|
+
validateConfiguredKey,
|
|
37
|
+
ensurePassphrase,
|
|
38
|
+
ensureKeyInAgent,
|
|
39
|
+
computeFingerprint,
|
|
40
|
+
promptPassphrase,
|
|
41
|
+
generateEd25519Key
|
|
42
|
+
} = await import('../lib/key.js')
|
|
43
|
+
|
|
44
|
+
const workspaceConfig = await this.$WorkspaceConfig.config
|
|
45
|
+
const keyConfig = await this.$SigningKeyConfig.config
|
|
46
|
+
const sshDir = await this.Home.sshDir
|
|
47
|
+
|
|
48
|
+
// --- Already configured: validate ---
|
|
49
|
+
if (keyConfig?.name && keyConfig?.privateKeyPath && keyConfig?.publicKey && keyConfig?.keyFingerprint) {
|
|
50
|
+
const valid = await validateConfiguredKey(keyConfig, 'Signing Key')
|
|
51
|
+
if (!valid) {
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
keyName: keyConfig.name,
|
|
56
|
+
privateKeyPath: keyConfig.privateKeyPath,
|
|
57
|
+
publicKey: keyConfig.publicKey,
|
|
58
|
+
keyFingerprint: keyConfig.keyFingerprint
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// --- Not configured: discover or create ---
|
|
63
|
+
console.log(chalk.cyan(`\n🔏 Signing Key Setup\n`))
|
|
64
|
+
console.log(chalk.gray(` Workspace: ${workspaceConfig?.name || 'unknown'}`))
|
|
65
|
+
console.log(chalk.gray(` Root: ${workspaceConfig?.rootDir || 'unknown'}`))
|
|
66
|
+
console.log(chalk.gray(''))
|
|
67
|
+
console.log(chalk.gray(' The signing key is an Ed25519 SSH key used for code and artifact signing.'))
|
|
68
|
+
console.log(chalk.gray(` You can select an existing key from ${sshDir} or create a new one.`))
|
|
69
|
+
console.log(chalk.gray(''))
|
|
70
|
+
|
|
71
|
+
// Discover existing Ed25519 keys in ~/.ssh
|
|
72
|
+
const existingKeys = await discoverEd25519Keys(sshDir)
|
|
73
|
+
|
|
74
|
+
// Build choices
|
|
75
|
+
const choices: Array<{ name: string; value: any }> = []
|
|
76
|
+
|
|
77
|
+
for (const key of existingKeys) {
|
|
78
|
+
choices.push({
|
|
79
|
+
name: `${key.name} ${chalk.gray(key.publicKey.substring(0, 60) + '...')}`,
|
|
80
|
+
value: { type: 'existing', ...key }
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
choices.push({
|
|
85
|
+
name: chalk.yellow('+ Create a new Ed25519 key'),
|
|
86
|
+
value: { type: 'create' }
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const selected = await this.WorkspacePrompt.select({
|
|
90
|
+
message: 'Select an Ed25519 key for signing:',
|
|
91
|
+
choices,
|
|
92
|
+
defaultValue: { type: 'create' },
|
|
93
|
+
pageSize: 15
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
let keyName: string
|
|
97
|
+
let privateKeyPath: string
|
|
98
|
+
let publicKey: string
|
|
99
|
+
let keyFingerprint: string
|
|
100
|
+
|
|
101
|
+
if (selected.type === 'existing') {
|
|
102
|
+
keyName = selected.name
|
|
103
|
+
privateKeyPath = selected.privateKeyPath
|
|
104
|
+
publicKey = selected.publicKey
|
|
105
|
+
keyFingerprint = computeFingerprint(selected.privateKeyPath)
|
|
106
|
+
|
|
107
|
+
// Ensure selected existing key has a passphrase
|
|
108
|
+
const passphraseOk = await ensurePassphrase(privateKeyPath, keyName, 'Signing key')
|
|
109
|
+
if (!passphraseOk) {
|
|
110
|
+
return null
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Add to ssh-agent
|
|
114
|
+
await ensureKeyInAgent(privateKeyPath, keyName, 'Signing key')
|
|
115
|
+
} else {
|
|
116
|
+
// Prompt for key name
|
|
117
|
+
keyName = await this.WorkspacePrompt.input({
|
|
118
|
+
message: 'Enter a name for the new signing key:',
|
|
119
|
+
defaultValue: 'id_t44_signing_ed25519',
|
|
120
|
+
validate: (input: string) => {
|
|
121
|
+
if (!input || input.trim().length === 0) {
|
|
122
|
+
return 'Key name cannot be empty'
|
|
123
|
+
}
|
|
124
|
+
if (!/^[a-zA-Z0-9_.-]+$/.test(input)) {
|
|
125
|
+
return 'Key name can only contain letters, numbers, underscores, dots, and hyphens'
|
|
126
|
+
}
|
|
127
|
+
return true
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
privateKeyPath = join(sshDir, keyName)
|
|
132
|
+
|
|
133
|
+
// Check if file already exists
|
|
134
|
+
let exists = false
|
|
135
|
+
try {
|
|
136
|
+
await statFile(privateKeyPath)
|
|
137
|
+
exists = true
|
|
138
|
+
} catch { }
|
|
139
|
+
|
|
140
|
+
if (exists) {
|
|
141
|
+
console.log(chalk.red(`\n ✗ File already exists: ${privateKeyPath}`))
|
|
142
|
+
console.log(chalk.red(` Choose a different name or select the existing key.\n`))
|
|
143
|
+
return null
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Prompt for passphrase
|
|
147
|
+
console.log(chalk.cyan(`\n Generating Ed25519 signing key '${keyName}'...`))
|
|
148
|
+
console.log(chalk.gray(` The key will be protected with a passphrase and added to the macOS Keychain.\n`))
|
|
149
|
+
|
|
150
|
+
const envPassphrase = process.env.T44_KEYS_PASSPHRASE
|
|
151
|
+
const passphrase = envPassphrase || await promptPassphrase()
|
|
152
|
+
if (!passphrase) {
|
|
153
|
+
console.log(chalk.red(`\n ✗ A passphrase is required for the signing key.\n`))
|
|
154
|
+
return null
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const result = await generateEd25519Key(privateKeyPath, passphrase, 't44-signing-key')
|
|
158
|
+
if (!result) {
|
|
159
|
+
return null
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
publicKey = result.publicKey
|
|
163
|
+
keyFingerprint = result.keyFingerprint
|
|
164
|
+
|
|
165
|
+
console.log(chalk.green(` ✓ Signing key generated:`))
|
|
166
|
+
console.log(chalk.green(` ${privateKeyPath}`))
|
|
167
|
+
console.log(chalk.green(` ${privateKeyPath}.pub\n`))
|
|
168
|
+
|
|
169
|
+
// Add the new key to the ssh-agent with Keychain storage
|
|
170
|
+
if (!envPassphrase) {
|
|
171
|
+
await ensureKeyInAgent(privateKeyPath, keyName, 'Signing key')
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Store in config
|
|
176
|
+
await this.$SigningKeyConfig.setConfigValue(['name'], keyName)
|
|
177
|
+
await this.$SigningKeyConfig.setConfigValue(['privateKeyPath'], privateKeyPath)
|
|
178
|
+
await this.$SigningKeyConfig.setConfigValue(['publicKey'], publicKey)
|
|
179
|
+
await this.$SigningKeyConfig.setConfigValue(['keyFingerprint'], keyFingerprint)
|
|
180
|
+
|
|
181
|
+
console.log(chalk.green(` ✓ Signing key configured: ${keyName}`))
|
|
182
|
+
console.log(chalk.green(` ${keyFingerprint}\n`))
|
|
183
|
+
|
|
184
|
+
return { keyName, privateKeyPath, publicKey, keyFingerprint }
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
getKeyPath: {
|
|
188
|
+
type: CapsulePropertyTypes.Function,
|
|
189
|
+
value: async function (this: any): Promise<string | null> {
|
|
190
|
+
const keyConfig = await this.$SigningKeyConfig.config
|
|
191
|
+
|
|
192
|
+
if (!keyConfig?.privateKeyPath) {
|
|
193
|
+
return null
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return keyConfig.privateKeyPath
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
getPublicKey: {
|
|
200
|
+
type: CapsulePropertyTypes.Function,
|
|
201
|
+
value: async function (this: any): Promise<string | null> {
|
|
202
|
+
const keyConfig = await this.$SigningKeyConfig.config
|
|
203
|
+
|
|
204
|
+
if (!keyConfig?.publicKey) {
|
|
205
|
+
return null
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return keyConfig.publicKey
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
getFingerprint: {
|
|
212
|
+
type: CapsulePropertyTypes.Function,
|
|
213
|
+
value: async function (this: any): Promise<string | null> {
|
|
214
|
+
const keyConfig = await this.$SigningKeyConfig.config
|
|
215
|
+
|
|
216
|
+
if (!keyConfig?.keyFingerprint) {
|
|
217
|
+
return null
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return keyConfig.keyFingerprint
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
getKeyName: {
|
|
224
|
+
type: CapsulePropertyTypes.Function,
|
|
225
|
+
value: async function (this: any): Promise<string | null> {
|
|
226
|
+
const keyConfig = await this.$SigningKeyConfig.config
|
|
227
|
+
|
|
228
|
+
if (!keyConfig?.name) {
|
|
229
|
+
return null
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return keyConfig.name
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}, {
|
|
238
|
+
importMeta: import.meta,
|
|
239
|
+
importStack: makeImportStack(),
|
|
240
|
+
capsuleName: capsule['#'],
|
|
241
|
+
})
|
|
242
|
+
}
|
|
243
|
+
capsule['#'] = '@stream44.studio/t44/caps/SigningKey'
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
|
|
2
|
+
type TaskType = 'serial' | 'parallel' | 'step';
|
|
3
|
+
|
|
4
|
+
type Task = {
|
|
5
|
+
type: TaskType;
|
|
6
|
+
name: string;
|
|
7
|
+
fn: () => void | Promise<void>;
|
|
8
|
+
children: Task[];
|
|
9
|
+
timeout?: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export async function capsule({
|
|
13
|
+
encapsulate,
|
|
14
|
+
CapsulePropertyTypes,
|
|
15
|
+
makeImportStack
|
|
16
|
+
}: {
|
|
17
|
+
encapsulate: any
|
|
18
|
+
CapsulePropertyTypes: any
|
|
19
|
+
makeImportStack: any
|
|
20
|
+
}) {
|
|
21
|
+
return encapsulate({
|
|
22
|
+
'#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
|
|
23
|
+
'#@stream44.studio/encapsulate/structs/Capsule': {},
|
|
24
|
+
'#': {
|
|
25
|
+
|
|
26
|
+
lib: {
|
|
27
|
+
type: CapsulePropertyTypes.Mapping,
|
|
28
|
+
value: '@stream44.studio/t44/caps/ProjectTestLib',
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
_rootTasks: {
|
|
32
|
+
type: CapsulePropertyTypes.Literal,
|
|
33
|
+
value: [] as Task[],
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
_currentParent: {
|
|
37
|
+
type: CapsulePropertyTypes.Literal,
|
|
38
|
+
value: null as Task | null,
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
_breadcrumb: {
|
|
42
|
+
type: CapsulePropertyTypes.Literal,
|
|
43
|
+
value: [] as string[],
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
exitOnComplete: {
|
|
47
|
+
type: CapsulePropertyTypes.Literal,
|
|
48
|
+
value: true,
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
serial: {
|
|
52
|
+
type: CapsulePropertyTypes.Function,
|
|
53
|
+
value: function (this: any, name: string, fn: () => void | Promise<void>) {
|
|
54
|
+
const task: Task = {
|
|
55
|
+
type: 'serial',
|
|
56
|
+
name,
|
|
57
|
+
fn,
|
|
58
|
+
children: []
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (this._currentParent) {
|
|
62
|
+
this._currentParent.children.push(task);
|
|
63
|
+
} else {
|
|
64
|
+
this._rootTasks.push(task);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const previousParent = this._currentParent;
|
|
68
|
+
this._currentParent = task;
|
|
69
|
+
fn();
|
|
70
|
+
this._currentParent = previousParent;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
parallel: {
|
|
75
|
+
type: CapsulePropertyTypes.Function,
|
|
76
|
+
value: function (this: any, name: string, fn: () => void | Promise<void>) {
|
|
77
|
+
const task: Task = {
|
|
78
|
+
type: 'parallel',
|
|
79
|
+
name,
|
|
80
|
+
fn,
|
|
81
|
+
children: []
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
if (this._currentParent) {
|
|
85
|
+
this._currentParent.children.push(task);
|
|
86
|
+
} else {
|
|
87
|
+
this._rootTasks.push(task);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const previousParent = this._currentParent;
|
|
91
|
+
this._currentParent = task;
|
|
92
|
+
fn();
|
|
93
|
+
this._currentParent = previousParent;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
step: {
|
|
98
|
+
type: CapsulePropertyTypes.Function,
|
|
99
|
+
value: function (this: any, name: string, fn: () => void | Promise<void>, timeout?: number) {
|
|
100
|
+
const task: Task = {
|
|
101
|
+
type: 'step',
|
|
102
|
+
name,
|
|
103
|
+
fn,
|
|
104
|
+
children: [],
|
|
105
|
+
timeout,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
if (this._currentParent) {
|
|
109
|
+
this._currentParent.children.push(task);
|
|
110
|
+
} else {
|
|
111
|
+
this._rootTasks.push(task);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
_executeTask: {
|
|
117
|
+
type: CapsulePropertyTypes.Function,
|
|
118
|
+
value: async function (this: any, task: Task): Promise<void> {
|
|
119
|
+
const previousBreadcrumb = [...this._breadcrumb];
|
|
120
|
+
this._breadcrumb.push(task.name);
|
|
121
|
+
const trail = this._breadcrumb.join(' -> ');
|
|
122
|
+
|
|
123
|
+
const colors = {
|
|
124
|
+
reset: '\x1b[0m',
|
|
125
|
+
blue: '\x1b[34m',
|
|
126
|
+
cyan: '\x1b[36m',
|
|
127
|
+
magenta: '\x1b[35m',
|
|
128
|
+
green: '\x1b[32m',
|
|
129
|
+
red: '\x1b[31m',
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
let startSymbol = '▶';
|
|
133
|
+
let color = colors.reset;
|
|
134
|
+
|
|
135
|
+
if (task.type === 'serial') {
|
|
136
|
+
startSymbol = '⚡';
|
|
137
|
+
color = colors.blue;
|
|
138
|
+
} else if (task.type === 'parallel') {
|
|
139
|
+
startSymbol = '⚙';
|
|
140
|
+
color = colors.magenta;
|
|
141
|
+
} else {
|
|
142
|
+
startSymbol = '▸';
|
|
143
|
+
color = colors.cyan;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log(`${color}${startSymbol} ${trail}${colors.reset}`);
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
if (task.type === 'serial') {
|
|
150
|
+
for (const child of task.children) {
|
|
151
|
+
await this._executeTask(child);
|
|
152
|
+
}
|
|
153
|
+
} else if (task.type === 'parallel') {
|
|
154
|
+
await Promise.all(task.children.map((child: Task) => this._executeTask(child)));
|
|
155
|
+
} else {
|
|
156
|
+
await task.fn();
|
|
157
|
+
}
|
|
158
|
+
console.log(`${colors.green}✓ ${trail}${colors.reset}`);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.log(`${colors.red}✗ ${trail}${colors.reset}`);
|
|
161
|
+
throw error;
|
|
162
|
+
} finally {
|
|
163
|
+
this._breadcrumb = previousBreadcrumb;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
run: {
|
|
169
|
+
type: CapsulePropertyTypes.Function,
|
|
170
|
+
value: async function (this: any): Promise<void> {
|
|
171
|
+
try {
|
|
172
|
+
for (const task of this._rootTasks) {
|
|
173
|
+
await this._executeTask(task);
|
|
174
|
+
}
|
|
175
|
+
} finally {
|
|
176
|
+
this._rootTasks = [];
|
|
177
|
+
this._breadcrumb = [];
|
|
178
|
+
this._currentParent = null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (this.exitOnComplete) process.exit(0);
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}, {
|
|
187
|
+
importMeta: import.meta,
|
|
188
|
+
importStack: makeImportStack(),
|
|
189
|
+
capsuleName: capsule['#'],
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
capsule['#'] = '@stream44.studio/t44/caps/TaskWorkflow'
|