t44 0.2.0-rc.1

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.

Potentially problematic release.


This version of t44 might be problematic. Click here for more details.

Files changed (86) hide show
  1. package/LICENSE.md +203 -0
  2. package/README.md +154 -0
  3. package/bin/activate +36 -0
  4. package/bin/activate.ts +30 -0
  5. package/bin/postinstall.sh +19 -0
  6. package/bin/shell +27 -0
  7. package/bin/t44 +27 -0
  8. package/caps/HomeRegistry.v0.ts +298 -0
  9. package/caps/OpenApiSchema.v0.ts +192 -0
  10. package/caps/ProjectDeployment.v0.ts +363 -0
  11. package/caps/ProjectDevelopment.v0.ts +246 -0
  12. package/caps/ProjectPublishing.v0.ts +307 -0
  13. package/caps/ProjectRack.v0.ts +128 -0
  14. package/caps/WorkspaceCli.v0.ts +391 -0
  15. package/caps/WorkspaceConfig.v0.ts +626 -0
  16. package/caps/WorkspaceConfig.yaml +53 -0
  17. package/caps/WorkspaceConnection.v0.ts +240 -0
  18. package/caps/WorkspaceEntityConfig.v0.ts +64 -0
  19. package/caps/WorkspaceEntityFact.v0.ts +193 -0
  20. package/caps/WorkspaceInfo.v0.ts +554 -0
  21. package/caps/WorkspaceInit.v0.ts +30 -0
  22. package/caps/WorkspaceKey.v0.ts +186 -0
  23. package/caps/WorkspaceProjects.v0.ts +455 -0
  24. package/caps/WorkspacePrompt.v0.ts +396 -0
  25. package/caps/WorkspaceShell.sh +39 -0
  26. package/caps/WorkspaceShell.v0.ts +104 -0
  27. package/caps/WorkspaceShell.yaml +65 -0
  28. package/caps/WorkspaceShellCli.v0.ts +109 -0
  29. package/caps/WorkspaceTest.v0.ts +167 -0
  30. package/caps/providers/LICENSE.md +8 -0
  31. package/caps/providers/README.md +2 -0
  32. package/caps/providers/bunny.net/ProjectDeployment.v0.ts +328 -0
  33. package/caps/providers/bunny.net/api-pull.v0.test.ts +319 -0
  34. package/caps/providers/bunny.net/api-pull.v0.ts +161 -0
  35. package/caps/providers/bunny.net/api-storage.v0.test.ts +168 -0
  36. package/caps/providers/bunny.net/api-storage.v0.ts +245 -0
  37. package/caps/providers/bunny.net/api.v0.ts +95 -0
  38. package/caps/providers/dynadot.com/ProjectDeployment.v0.ts +207 -0
  39. package/caps/providers/dynadot.com/api-domains.v0.test.ts +147 -0
  40. package/caps/providers/dynadot.com/api-domains.v0.ts +137 -0
  41. package/caps/providers/dynadot.com/api.v0.ts +88 -0
  42. package/caps/providers/git-scm.com/ProjectPublishing.v0.ts +231 -0
  43. package/caps/providers/github.com/ProjectPublishing.v0.ts +75 -0
  44. package/caps/providers/github.com/api.v0.ts +90 -0
  45. package/caps/providers/npmjs.com/ProjectPublishing.v0.ts +741 -0
  46. package/caps/providers/vercel.com/ProjectDeployment.v0.ts +339 -0
  47. package/caps/providers/vercel.com/api.v0.test.ts +67 -0
  48. package/caps/providers/vercel.com/api.v0.ts +132 -0
  49. package/caps/providers/vercel.com/bun.lock +194 -0
  50. package/caps/providers/vercel.com/package.json +10 -0
  51. package/caps/providers/vercel.com/project.v0.test.ts +108 -0
  52. package/caps/providers/vercel.com/project.v0.ts +150 -0
  53. package/caps/providers/vercel.com/tsconfig.json +28 -0
  54. package/docs/Overview.drawio +189 -0
  55. package/docs/Overview.svg +4 -0
  56. package/lib/crypto.ts +53 -0
  57. package/lib/openapi.ts +132 -0
  58. package/lib/ucan.ts +137 -0
  59. package/package.json +41 -0
  60. package/structs/HomeRegistryConfig.v0.ts +27 -0
  61. package/structs/ProjectDeploymentConfig.v0.ts +27 -0
  62. package/structs/ProjectDeploymentFact.v0.ts +110 -0
  63. package/structs/ProjectPublishingFact.v0.ts +69 -0
  64. package/structs/ProjectRackConfig.v0.ts +27 -0
  65. package/structs/WorkspaceCliConfig.v0.ts +27 -0
  66. package/structs/WorkspaceConfig.v0.ts +27 -0
  67. package/structs/WorkspaceKeyConfig.v0.ts +27 -0
  68. package/structs/WorkspaceMappings.v0.ts +27 -0
  69. package/structs/WorkspaceProjectsConfig.v0.ts +27 -0
  70. package/structs/WorkspaceRepositories.v0.ts +27 -0
  71. package/structs/WorkspaceShellConfig.v0.ts +45 -0
  72. package/structs/providers/LICENSE.md +8 -0
  73. package/structs/providers/README.md +2 -0
  74. package/structs/providers/bunny.net/ProjectDeploymentFact.v0.ts +41 -0
  75. package/structs/providers/bunny.net/WorkspaceConnectionConfig.v0.ts +42 -0
  76. package/structs/providers/dynadot.com/DomainFact.v0.ts +146 -0
  77. package/structs/providers/dynadot.com/WorkspaceConnectionConfig.v0.ts +41 -0
  78. package/structs/providers/git-scm.com/ProjectPublishingFact.v0.ts +46 -0
  79. package/structs/providers/github.com/ProjectPublishingFact.v0.ts +52 -0
  80. package/structs/providers/github.com/WorkspaceConnectionConfig.v0.ts +42 -0
  81. package/structs/providers/npmjs.com/ProjectPublishingFact.v0.ts +48 -0
  82. package/structs/providers/vercel.com/ProjectDeploymentFact.v0.ts +38 -0
  83. package/structs/providers/vercel.com/WorkspaceConnectionConfig.v0.ts +48 -0
  84. package/tsconfig.json +28 -0
  85. package/workspace-rt.ts +134 -0
  86. package/workspace.yaml +5 -0
@@ -0,0 +1,396 @@
1
+
2
+ // Global prompt queue to ensure sequential prompting and deduplication
3
+ const globalPromptQueue: Array<() => Promise<any>> = []
4
+ const globalActivePrompts: Record<string, Promise<any>> = {}
5
+ const globalShownTitles: Set<string> = new Set()
6
+ let globalIsProcessing = false
7
+
8
+ async function processGlobalQueue() {
9
+ if (globalIsProcessing || globalPromptQueue.length === 0) return
10
+ globalIsProcessing = true
11
+
12
+ while (globalPromptQueue.length > 0) {
13
+ const task = globalPromptQueue.shift()!
14
+ await task()
15
+ }
16
+
17
+ globalIsProcessing = false
18
+ }
19
+
20
+ export async function capsule({
21
+ encapsulate,
22
+ CapsulePropertyTypes,
23
+ makeImportStack
24
+ }: {
25
+ encapsulate: any
26
+ CapsulePropertyTypes: any
27
+ makeImportStack: any
28
+ }) {
29
+ return encapsulate({
30
+ '#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0': {
31
+ '#@stream44.studio/encapsulate/structs/Capsule.v0': {},
32
+ '#': {
33
+ WorkspaceCli: {
34
+ type: CapsulePropertyTypes.Mapping,
35
+ value: 't44/caps/WorkspaceCli.v0'
36
+ },
37
+ WorkspaceTest: {
38
+ type: CapsulePropertyTypes.Mapping,
39
+ value: 't44/caps/WorkspaceTest.v0'
40
+ },
41
+ prompt: {
42
+ type: CapsulePropertyTypes.Function,
43
+ value: async function (this: any, questions: any[]): Promise<any> {
44
+ // Check if --yes flag is set
45
+ const cliOptions = await this.WorkspaceCli.cliOptions
46
+ const yes = cliOptions?.yes || false
47
+
48
+ // If --yes is set, return default values
49
+ if (yes) {
50
+ const result: Record<string, any> = {}
51
+ for (const question of questions) {
52
+ result[question.name] = question.default
53
+ }
54
+ return result
55
+ }
56
+
57
+ // Otherwise, load inquirer and prompt user
58
+ const inquirer = await import('inquirer')
59
+ try {
60
+ return await inquirer.default.prompt(questions)
61
+ } catch (error: any) {
62
+ if (error.message?.includes('SIGINT') || error.message?.includes('force closed')) {
63
+ const chalk = (await import('chalk')).default
64
+ console.log(chalk.red('\n\nABORTED\n'))
65
+ process.exit(0)
66
+ }
67
+ throw error
68
+ }
69
+ }
70
+ },
71
+ confirm: {
72
+ type: CapsulePropertyTypes.Function,
73
+ value: async function (this: any, {
74
+ title,
75
+ description,
76
+ message,
77
+ defaultValue = false,
78
+ onSuccess,
79
+ onAbort
80
+ }: {
81
+ title?: string
82
+ description?: string | string[]
83
+ message: string
84
+ defaultValue?: boolean
85
+ onSuccess?: (confirmed: boolean) => Promise<void> | void
86
+ onAbort?: () => Promise<void> | void
87
+ }): Promise<boolean> {
88
+ const chalk = (await import('chalk')).default
89
+
90
+ if (title) {
91
+ console.log(chalk.cyan(`\n${title}\n`))
92
+ }
93
+ if (description) {
94
+ const lines = Array.isArray(description) ? description : [description]
95
+ for (const line of lines) {
96
+ console.log(chalk.gray(` ${line}`))
97
+ }
98
+ console.log('')
99
+ }
100
+
101
+ // Check if --yes flag is set
102
+ const cliOptions = await this.WorkspaceCli.cliOptions
103
+ const yes = cliOptions?.yes || false
104
+
105
+ let confirmed: boolean
106
+
107
+ // If --yes is set, return default value
108
+ if (yes) {
109
+ confirmed = defaultValue
110
+ } else {
111
+ try {
112
+ // Otherwise, load inquirer and prompt user
113
+ const inquirer = await import('inquirer')
114
+ const result = await inquirer.default.prompt([
115
+ {
116
+ type: 'confirm',
117
+ name: 'confirmed',
118
+ message,
119
+ default: defaultValue
120
+ }
121
+ ])
122
+ confirmed = result.confirmed
123
+ } catch (error: any) {
124
+ if (error.message?.includes('SIGINT') || error.message?.includes('force closed')) {
125
+ console.log(chalk.red('\n\nABORTED\n'))
126
+ if (onAbort) {
127
+ await onAbort()
128
+ }
129
+ process.exit(0)
130
+ }
131
+ throw error
132
+ }
133
+ }
134
+
135
+ if (onSuccess) {
136
+ await onSuccess(confirmed)
137
+ }
138
+
139
+ return confirmed
140
+ }
141
+ },
142
+ input: {
143
+ type: CapsulePropertyTypes.Function,
144
+ value: async function (this: any, {
145
+ message,
146
+ defaultValue,
147
+ validate,
148
+ promptFactId
149
+ }: {
150
+ message: string
151
+ defaultValue?: string
152
+ validate?: (input: string) => boolean | string
153
+ promptFactId?: string
154
+ }): Promise<string> {
155
+ // Try to get value from env first (works in both interactive and non-interactive modes)
156
+ if (promptFactId) {
157
+ const envValue = this.getEnvValueForFactReference(promptFactId)
158
+ if (envValue) {
159
+ return envValue
160
+ }
161
+ }
162
+
163
+ // In non-interactive mode, throw error if env value not found
164
+ if (!process.stdin.isTTY && promptFactId) {
165
+ throw new Error(
166
+ `Cannot prompt for "${message}" in non-interactive mode. ` +
167
+ `Please run interactively first to configure credentials, or set the corresponding env variable.`
168
+ )
169
+ }
170
+
171
+ // Check for existing prompt with same ID
172
+ if (promptFactId && promptFactId in globalActivePrompts) {
173
+ return globalActivePrompts[promptFactId]
174
+ }
175
+
176
+ // Create the prompt task
177
+ const promptTask = async () => {
178
+ try {
179
+ // Check if --yes flag is set
180
+ const cliOptions = await this.WorkspaceCli.cliOptions
181
+ const yes = cliOptions?.yes || false
182
+
183
+ // If --yes is set, return default value
184
+ if (yes) {
185
+ if (!defaultValue) {
186
+ throw new Error(`Cannot use --yes flag without a default value for prompt: ${message}`)
187
+ }
188
+ return defaultValue
189
+ }
190
+
191
+ // Otherwise, load inquirer and prompt user
192
+ const inquirer = await import('inquirer')
193
+ const question: any = {
194
+ type: 'input',
195
+ name: 'value',
196
+ message,
197
+ validate
198
+ }
199
+
200
+ // Only add default if explicitly provided
201
+ if (defaultValue !== undefined) {
202
+ question.default = defaultValue
203
+ }
204
+
205
+ const { value } = await inquirer.default.prompt([question])
206
+ return value
207
+ } catch (error: any) {
208
+ if (error.message?.includes('SIGINT') || error.message?.includes('force closed')) {
209
+ const chalk = (await import('chalk')).default
210
+ console.log(chalk.red('\n\nABORTED\n'))
211
+ process.exit(0)
212
+ }
213
+ throw error
214
+ } finally {
215
+ // Remove from active prompts when done
216
+ if (promptFactId) {
217
+ delete globalActivePrompts[promptFactId]
218
+ }
219
+ }
220
+ }
221
+
222
+ // Create promise and add to queue
223
+ const promise = new Promise<string>((resolve, reject) => {
224
+ globalPromptQueue.push(async () => {
225
+ try {
226
+ const result = await promptTask()
227
+ resolve(result)
228
+ } catch (error) {
229
+ reject(error)
230
+ }
231
+ })
232
+ })
233
+
234
+ // Track active prompt
235
+ if (promptFactId) {
236
+ globalActivePrompts[promptFactId] = promise
237
+ }
238
+
239
+ // Start processing queue (inlined to avoid ambient reference issues)
240
+ if (!globalIsProcessing && globalPromptQueue.length > 0) {
241
+ globalIsProcessing = true
242
+
243
+ // Process queue asynchronously
244
+ ; (async () => {
245
+ while (globalPromptQueue.length > 0) {
246
+ const task = globalPromptQueue.shift()!
247
+ await task()
248
+ }
249
+ globalIsProcessing = false
250
+ })()
251
+ }
252
+
253
+ return promise
254
+ }
255
+ },
256
+ getEnvValueForFactReference: {
257
+ type: CapsulePropertyTypes.Function,
258
+ value: function (this: any, factReference: string): string | undefined {
259
+ const workspaceTest = this.WorkspaceTest
260
+ if (!workspaceTest) return undefined
261
+
262
+ const envConfig = workspaceTest.env || {}
263
+
264
+ for (const [envVarName, envDef] of Object.entries(envConfig)) {
265
+ if ((envDef as any)?.factReference === factReference) {
266
+ return workspaceTest.getEnvValue(envVarName)
267
+ }
268
+ }
269
+ return undefined
270
+ }
271
+ },
272
+ select: {
273
+ type: CapsulePropertyTypes.Function,
274
+ value: async function (this: any, {
275
+ message,
276
+ choices,
277
+ defaultValue,
278
+ pageSize
279
+ }: {
280
+ message: string
281
+ choices: Array<{ name: string; value: any; disabled?: boolean | string }>
282
+ defaultValue?: any
283
+ pageSize?: number
284
+ }): Promise<any> {
285
+ // Check if --yes flag is set
286
+ const cliOptions = await this.WorkspaceCli.cliOptions
287
+ const yes = cliOptions?.yes || false
288
+
289
+ // If --yes is set, return default value
290
+ if (yes) {
291
+ if (defaultValue === undefined) {
292
+ throw new Error(`Cannot use --yes flag without a default value for select: ${message}`)
293
+ }
294
+ return defaultValue
295
+ }
296
+
297
+ // Otherwise, load inquirer and prompt user
298
+ const inquirer = await import('inquirer')
299
+ try {
300
+ const { value } = await inquirer.default.prompt([
301
+ {
302
+ type: 'list',
303
+ name: 'value',
304
+ message,
305
+ choices,
306
+ default: defaultValue,
307
+ pageSize: pageSize || 10
308
+ }
309
+ ])
310
+ return value
311
+ } catch (error: any) {
312
+ if (error.message?.includes('SIGINT') || error.message?.includes('force closed')) {
313
+ const chalk = (await import('chalk')).default
314
+ console.log(chalk.red('\n\nABORTED\n'))
315
+ process.exit(0)
316
+ }
317
+ throw error
318
+ }
319
+ }
320
+ },
321
+ setupPrompt: {
322
+ type: CapsulePropertyTypes.Function,
323
+ value: async function (this: any, {
324
+ title,
325
+ description,
326
+ message,
327
+ defaultValue,
328
+ validate,
329
+ configPath,
330
+ configKey,
331
+ onSuccess,
332
+ onAbort
333
+ }: {
334
+ title: string
335
+ description?: string | string[]
336
+ message: string
337
+ defaultValue: string
338
+ validate?: (input: string) => boolean | string
339
+ configPath: string[]
340
+ configKey?: string
341
+ onSuccess?: (value: string) => Promise<void> | void
342
+ onAbort?: () => Promise<void> | void
343
+ }): Promise<string> {
344
+ const chalk = (await import('chalk')).default
345
+
346
+ console.log(chalk.cyan(`\n${title}\n`))
347
+ if (description) {
348
+ const lines = Array.isArray(description) ? description : [description]
349
+ for (const line of lines) {
350
+ console.log(chalk.gray(` ${line}`))
351
+ }
352
+ console.log('')
353
+ }
354
+
355
+ try {
356
+ const value = await this.input({
357
+ message,
358
+ defaultValue,
359
+ validate
360
+ })
361
+
362
+ if (onSuccess) {
363
+ await onSuccess(value)
364
+ }
365
+
366
+ const displayKey = configKey || configPath.join('.')
367
+ console.log(chalk.green(`\n ✓ Updated config with ${displayKey}: ${value}\n`))
368
+
369
+ return value
370
+ } catch (error: any) {
371
+ if (error.message?.includes('SIGINT') || error.message?.includes('force closed')) {
372
+ console.log(chalk.red('\n\nABORTED\n'))
373
+ if (onAbort) {
374
+ await onAbort()
375
+ }
376
+ process.exit(0)
377
+ }
378
+ throw error
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+ }, {
385
+ importMeta: import.meta,
386
+ importStack: makeImportStack(),
387
+ capsuleName: capsule['#'],
388
+ ambientReferences: {
389
+ globalPromptQueue,
390
+ globalActivePrompts,
391
+ globalShownTitles,
392
+ globalIsProcessing
393
+ }
394
+ })
395
+ }
396
+ capsule['#'] = 't44/caps/WorkspacePrompt.v0'
@@ -0,0 +1,39 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ function w_log {
6
+ if [[ "$1" == "var" ]]; then
7
+ echo "\033[1;37m[$F_WORKSPACE_BASENAME] $2\033[0m"
8
+ elif [[ "$1" == "info" ]]; then
9
+ echo "\033[0;36m[$F_WORKSPACE_BASENAME] $2\033[0m"
10
+ elif [[ "$1" == "start" ]]; then
11
+ echo "\033[0;36m[$F_WORKSPACE_BASENAME] $2 ...\033[0m"
12
+ elif [[ "$1" == "notice" ]]; then
13
+ echo "\n\033[0;36m[$F_WORKSPACE_BASENAME] NOTICE: $2 ...\033[0m\n"
14
+ elif [[ "$1" == "success" ]]; then
15
+ echo "\033[0;32m[$F_WORKSPACE_BASENAME] $2\033[0m"
16
+ elif [[ "$1" == "error" ]]; then
17
+ echo "\033[0;31m[$F_WORKSPACE_BASENAME] $2\033[0m" >&2
18
+ fi
19
+ }
20
+
21
+ function initWorkspace {
22
+
23
+ #${COMMANDS}
24
+
25
+ }
26
+
27
+
28
+ if [ -z "$F_WORKSPACE_DIR" ]; then
29
+ w_log "error" "ERROR: 'F_WORKSPACE_DIR' env var not set!"
30
+ else
31
+
32
+ if [ -z "$F_WORKSPACE_BASENAME" ]; then
33
+ export F_WORKSPACE_BASENAME="$(basename "${F_WORKSPACE_DIR}")"
34
+ fi
35
+
36
+ initWorkspace ${@:1}
37
+ fi
38
+
39
+ set +e
@@ -0,0 +1,104 @@
1
+
2
+ import { join, resolve, relative } from 'path'
3
+ import { readFile } from 'fs/promises'
4
+ import { $ } from 'bun'
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.v0': {},
18
+ '#t44/structs/WorkspaceCliConfig.v0': {
19
+ as: '$WorkspaceCliConfig'
20
+ },
21
+ '#t44/structs/WorkspaceShellConfig.v0': {
22
+ as: '$ShellConfig'
23
+ },
24
+ '#': {
25
+ WorkspaceConfig: {
26
+ type: CapsulePropertyTypes.Mapping,
27
+ value: 't44/caps/WorkspaceConfig.v0'
28
+ },
29
+ run: {
30
+ type: CapsulePropertyTypes.Function,
31
+ value: async function (this: any, { args }: any): Promise<void> {
32
+
33
+ const env = await this.$ShellConfig.env
34
+ const config = await this.WorkspaceConfig.config as any
35
+ const cliConfig = await this.$WorkspaceCliConfig.config
36
+
37
+ for (const name in env) {
38
+ process.stdout.write(`export ${name}="${env[name]}"\n`)
39
+ }
40
+
41
+ process.stdout.write('\n')
42
+
43
+ // Load the shell script template
44
+ const shellScriptModule = import.meta.resolve('t44/caps/WorkspaceShell.sh')
45
+ const shellScriptPath = shellScriptModule.replace('file://', '')
46
+ let shellScript = await readFile(shellScriptPath, 'utf-8')
47
+
48
+ // Generate commands dynamically from shell.commands
49
+ const shellConfig = await this.$ShellConfig.config
50
+ const shellCommands = shellConfig?.shell?.commands || {}
51
+ const cliCommands = cliConfig?.cli?.commands || {}
52
+ const commandNames = Object.keys(shellCommands).sort()
53
+
54
+ // Generate shell functions
55
+ const helpLines: string[] = []
56
+ for (const cmdName of commandNames) {
57
+ const cmdConfig = shellCommands[cmdName]
58
+
59
+ let cmdBody = ''
60
+
61
+ // Check if this is a cliCommand reference
62
+ if (cmdConfig.cliCommand) {
63
+ const cliCommandName = cmdConfig.cliCommand
64
+ // Auto-generate the shell code to call the CLI command
65
+ cmdBody = `(
66
+ cd "$F_WORKSPACE_DIR" &&
67
+ "\${F_WORKSPACE_IMPL_DIR}/bin/workspace" ${cliCommandName} \$@
68
+ )`
69
+ } else {
70
+ cmdBody = cmdConfig.cmd || ''
71
+ }
72
+
73
+ helpLines.push(` function ${cmdName} {`)
74
+ for (const line of cmdBody.split('\n')) {
75
+ helpLines.push(` ${line}`)
76
+ }
77
+ helpLines.push(` }`)
78
+ helpLines.push(``)
79
+ }
80
+
81
+ // Generate alias for h if it exists
82
+ if (shellCommands.h) {
83
+ helpLines.push(` alias h='cd "\${F_WORKSPACE_DIR}"'`)
84
+ helpLines.push(``)
85
+ }
86
+
87
+ const commandsBlock = helpLines.join('\n')
88
+
89
+ // Replace the placeholder in the shell script
90
+ shellScript = shellScript.replace('#${COMMANDS}', commandsBlock)
91
+
92
+ // Remove the shebang line and output
93
+ process.stdout.write(shellScript.split('\n').slice(1).join('\n'))
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }, {
99
+ importMeta: import.meta,
100
+ importStack: makeImportStack(),
101
+ capsuleName: capsule['#'],
102
+ })
103
+ }
104
+ capsule['#'] = 't44/caps/WorkspaceShell.v0'
@@ -0,0 +1,65 @@
1
+ "#t44/structs/WorkspaceShellConfig.v0":
2
+ env:
3
+ default:
4
+ force:
5
+ F_WORKSPACE_DIR: resolve('${__dirname}/..')
6
+ shell:
7
+ commands:
8
+ help:
9
+ description: "Display help for shell commands."
10
+ cmd: |
11
+ "${F_WORKSPACE_IMPL_DIR}/bin/shell" --help
12
+ 44:
13
+ description: "Run workspace CLI commands."
14
+ cmd: |
15
+ "${F_WORKSPACE_IMPL_DIR}/bin/workspace" $@
16
+
17
+ a:
18
+ description: "Re-activate workspace environment."
19
+ cmd: |
20
+ w_log "start" "Re-activating workspace"
21
+
22
+ source "$F_WORKSPACE_ACTIVATE_BIN_PATH"
23
+
24
+ w_log "success" "Workspace Activated OK!"
25
+
26
+ i:
27
+ description: "Re-install workspace dependencies (removes node_modules and runs bun install)."
28
+ cmd: |
29
+ w_log "start" "Re-installing workspace"
30
+
31
+ (
32
+ cd "${F_WORKSPACE_DIR}" &&
33
+ find . -name 'node_modules' -type d -prune -exec rm -rf {} + 2>/dev/null || true &&
34
+ bun install
35
+ )
36
+
37
+ w_log "success" "Workspace Re-installed OK!"
38
+
39
+ info:
40
+ description: "Display workspace information."
41
+ cmd: |
42
+ (
43
+ cd "${F_WORKSPACE_DIR}" &&
44
+ "${F_WORKSPACE_IMPL_DIR}/bin/workspace" info ${@:2}
45
+ )
46
+
47
+ p:
48
+ description: "Push project repositories."
49
+ cmd: |
50
+ w_log "start" "Push project repositories"
51
+
52
+ (
53
+ cd "${F_WORKSPACE_DIR}" &&
54
+ "${F_WORKSPACE_IMPL_DIR}/bin/workspace" push $@
55
+ )
56
+
57
+ w_log "success" "Project repositories pushed OK!"
58
+
59
+ h:
60
+ description: "Navigate to workspace home directory."
61
+ cmd: |
62
+ cd "${F_WORKSPACE_DIR}"
63
+
64
+ deploy:
65
+ cliCommand: "deploy"