@studio-foundation/cli 0.3.0-beta.1 → 0.3.0-beta.5
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/package.json +8 -5
- package/ARCHITECTURE.md +0 -40
- package/src/commands/api.ts +0 -126
- package/src/commands/config.ts +0 -433
- package/src/commands/init.ts +0 -879
- package/src/commands/install.ts +0 -23
- package/src/commands/integrations.ts +0 -332
- package/src/commands/list.ts +0 -197
- package/src/commands/logs.ts +0 -119
- package/src/commands/ollama.ts +0 -168
- package/src/commands/project.ts +0 -167
- package/src/commands/registry/audit.ts +0 -87
- package/src/commands/registry/index.ts +0 -63
- package/src/commands/registry/install.ts +0 -222
- package/src/commands/registry/publish.ts +0 -112
- package/src/commands/registry/remove.ts +0 -89
- package/src/commands/registry/search.ts +0 -93
- package/src/commands/registry/sync.ts +0 -24
- package/src/commands/registry/update.ts +0 -63
- package/src/commands/replay.ts +0 -559
- package/src/commands/run.ts +0 -454
- package/src/commands/status.ts +0 -163
- package/src/commands/template/index.ts +0 -59
- package/src/commands/template/validate.ts +0 -175
- package/src/commands/templates.ts +0 -99
- package/src/commands/tools.ts +0 -227
- package/src/commands/users.ts +0 -127
- package/src/commands/validate.ts +0 -46
- package/src/config.ts +0 -101
- package/src/index.ts +0 -201
- package/src/models-cache.ts +0 -127
- package/src/output/file-changes.ts +0 -97
- package/src/output/formatter.ts +0 -85
- package/src/output/formatters.ts +0 -303
- package/src/output/logger.ts +0 -18
- package/src/output/parallel-progress.ts +0 -103
- package/src/output/progress.ts +0 -414
- package/src/provider-validator.ts +0 -109
- package/src/registry/cache.ts +0 -46
- package/src/registry/client.ts +0 -84
- package/src/registry/lockfile.ts +0 -68
- package/src/registry/resolver.ts +0 -113
- package/src/registry/types.ts +0 -66
- package/src/run-logger.ts +0 -66
- package/src/run-store-factory.ts +0 -30
- package/src/studio-dir.ts +0 -28
- package/src/utils/input-wizard.ts +0 -73
- package/src/utils/placeholders.ts +0 -10
- package/templates/.studiorc.yaml +0 -16
- package/templates/projects/blank/metadata.json +0 -7
- package/templates/studio-config.yaml +0 -14
- package/tests/__stubs__/studio-runner.ts +0 -104
- package/tests/commands/api.test.ts +0 -110
- package/tests/commands/config.test.ts +0 -221
- package/tests/commands/init.test.ts +0 -919
- package/tests/commands/install.test.ts +0 -52
- package/tests/commands/integrations.test.ts +0 -158
- package/tests/commands/ollama.test.ts +0 -139
- package/tests/commands/project.test.ts +0 -179
- package/tests/commands/registry/audit.test.ts +0 -56
- package/tests/commands/registry/install.test.ts +0 -200
- package/tests/commands/registry/publish.test.ts +0 -56
- package/tests/commands/registry/remove.test.ts +0 -103
- package/tests/commands/registry/search.test.ts +0 -44
- package/tests/commands/registry/sync.test.ts +0 -37
- package/tests/commands/registry/update.test.ts +0 -62
- package/tests/commands/replay.test.ts +0 -283
- package/tests/commands/template/validate.test.ts +0 -150
- package/tests/commands/templates.test.ts +0 -42
- package/tests/commands/tools.test.ts +0 -106
- package/tests/config.test.ts +0 -142
- package/tests/formatter.test.ts +0 -158
- package/tests/integration/sigint.test.ts +0 -188
- package/tests/models-cache.test.ts +0 -250
- package/tests/output/file-changes.test.ts +0 -178
- package/tests/output/formatters.test.ts +0 -448
- package/tests/output/progress-spinner.test.ts +0 -232
- package/tests/output/progress-timer.test.ts +0 -230
- package/tests/provider-validator.test.ts +0 -182
- package/tests/registry/cache.test.ts +0 -66
- package/tests/registry/client.test.ts +0 -70
- package/tests/registry/lockfile.test.ts +0 -87
- package/tests/registry/resolver.test.ts +0 -122
- package/tests/run-logger-events.test.ts +0 -326
- package/tests/run-logger.test.ts +0 -64
- package/tests/run-store-factory.test.ts +0 -51
- package/tests/studio-dir.test.ts +0 -31
- package/tests/utils/input-wizard.test.ts +0 -153
- package/tests/utils/placeholders.test.ts +0 -36
- package/tsconfig.json +0 -24
- package/vitest.config.ts +0 -20
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import type { InputSchema } from '@studio-foundation/contracts';
|
|
3
|
-
import { collectStructuredInput } from '../../src/utils/input-wizard.js';
|
|
4
|
-
|
|
5
|
-
// Mock @inquirer/prompts at module level
|
|
6
|
-
vi.mock('@inquirer/prompts', () => ({
|
|
7
|
-
input: vi.fn(),
|
|
8
|
-
}));
|
|
9
|
-
import { validateInputSchema } from '../../src/utils/input-wizard.js';
|
|
10
|
-
|
|
11
|
-
describe('validateInputSchema', () => {
|
|
12
|
-
it('accepts a valid text field', () => {
|
|
13
|
-
const result = validateInputSchema({
|
|
14
|
-
type: 'structured',
|
|
15
|
-
fields: [{ name: 'brief_summary', type: 'text', prompt: 'Brief summary', required: true }],
|
|
16
|
-
});
|
|
17
|
-
expect(result.fields).toHaveLength(1);
|
|
18
|
-
expect(result.fields[0].name).toBe('brief_summary');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('accepts a valid array field', () => {
|
|
22
|
-
const result = validateInputSchema({
|
|
23
|
-
type: 'structured',
|
|
24
|
-
fields: [{ name: 'criteria', type: 'array', items: 'text', prompt: 'Criteria', required: true }],
|
|
25
|
-
});
|
|
26
|
-
expect(result.fields[0].type).toBe('array');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('accepts an optional field with a default', () => {
|
|
30
|
-
const result = validateInputSchema({
|
|
31
|
-
type: 'structured',
|
|
32
|
-
fields: [{ name: 'page', type: 'text', prompt: 'Target page', required: false, default: 'src/index.ts' }],
|
|
33
|
-
});
|
|
34
|
-
expect(result.fields[0].default).toBe('src/index.ts');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('throws when fields is missing', () => {
|
|
38
|
-
expect(() => validateInputSchema({ type: 'structured' })).toThrow(
|
|
39
|
-
'input_schema must have at least one field'
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('throws when fields is empty', () => {
|
|
44
|
-
expect(() => validateInputSchema({ type: 'structured', fields: [] })).toThrow(
|
|
45
|
-
'input_schema must have at least one field'
|
|
46
|
-
);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('throws when a field is missing prompt', () => {
|
|
50
|
-
expect(() =>
|
|
51
|
-
validateInputSchema({
|
|
52
|
-
type: 'structured',
|
|
53
|
-
fields: [{ name: 'foo', type: 'text', required: true }],
|
|
54
|
-
})
|
|
55
|
-
).toThrow("Field 'foo' must have a non-empty 'prompt'");
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('throws when a field has empty prompt', () => {
|
|
59
|
-
expect(() =>
|
|
60
|
-
validateInputSchema({
|
|
61
|
-
type: 'structured',
|
|
62
|
-
fields: [{ name: 'foo', type: 'text', prompt: ' ', required: true }],
|
|
63
|
-
})
|
|
64
|
-
).toThrow("Field 'foo' must have a non-empty 'prompt'");
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('throws when a field has invalid type', () => {
|
|
68
|
-
expect(() =>
|
|
69
|
-
validateInputSchema({
|
|
70
|
-
type: 'structured',
|
|
71
|
-
fields: [{ name: 'foo', type: 'number', prompt: 'Foo', required: true }],
|
|
72
|
-
})
|
|
73
|
-
).toThrow("Field 'foo' has invalid type 'number'. Must be 'text' or 'array'");
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('throws when an array field is missing items', () => {
|
|
77
|
-
expect(() =>
|
|
78
|
-
validateInputSchema({
|
|
79
|
-
type: 'structured',
|
|
80
|
-
fields: [{ name: 'foo', type: 'array', prompt: 'Foo', required: true }],
|
|
81
|
-
})
|
|
82
|
-
).toThrow("Array field 'foo' must have items: 'text'");
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('throws when an array field has non-text items', () => {
|
|
86
|
-
expect(() =>
|
|
87
|
-
validateInputSchema({
|
|
88
|
-
type: 'structured',
|
|
89
|
-
fields: [{ name: 'foo', type: 'array', items: 'number', prompt: 'Foo', required: true }],
|
|
90
|
-
})
|
|
91
|
-
).toThrow("Array field 'foo' must have items: 'text'");
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe('collectStructuredInput', () => {
|
|
96
|
-
beforeEach(() => {
|
|
97
|
-
vi.clearAllMocks();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('collects a single text field', async () => {
|
|
101
|
-
const { input: mockInput } = await import('@inquirer/prompts');
|
|
102
|
-
(mockInput as ReturnType<typeof vi.fn>).mockResolvedValueOnce('Add dark mode');
|
|
103
|
-
|
|
104
|
-
const schema: InputSchema = {
|
|
105
|
-
type: 'structured',
|
|
106
|
-
fields: [{ name: 'brief_summary', type: 'text', prompt: 'Brief summary', required: true }],
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const result = await collectStructuredInput(schema);
|
|
110
|
-
|
|
111
|
-
expect(result).toEqual({ brief_summary: 'Add dark mode' });
|
|
112
|
-
expect(mockInput).toHaveBeenCalledWith(
|
|
113
|
-
expect.objectContaining({ message: 'Brief summary' })
|
|
114
|
-
);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('collects an array field with multiple entries', async () => {
|
|
118
|
-
const { input: mockInput } = await import('@inquirer/prompts');
|
|
119
|
-
(mockInput as ReturnType<typeof vi.fn>)
|
|
120
|
-
.mockResolvedValueOnce('First criterion')
|
|
121
|
-
.mockResolvedValueOnce('Second criterion')
|
|
122
|
-
.mockResolvedValueOnce(''); // empty → stop
|
|
123
|
-
|
|
124
|
-
const schema: InputSchema = {
|
|
125
|
-
type: 'structured',
|
|
126
|
-
fields: [{ name: 'criteria', type: 'array', items: 'text', prompt: 'Criteria', required: true }],
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const result = await collectStructuredInput(schema);
|
|
130
|
-
|
|
131
|
-
expect(result).toEqual({ criteria: ['First criterion', 'Second criterion'] });
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('collects multiple fields', async () => {
|
|
135
|
-
const { input: mockInput } = await import('@inquirer/prompts');
|
|
136
|
-
(mockInput as ReturnType<typeof vi.fn>)
|
|
137
|
-
.mockResolvedValueOnce('Add dark mode') // text field
|
|
138
|
-
.mockResolvedValueOnce('Must work') // array entry 1
|
|
139
|
-
.mockResolvedValueOnce(''); // array stop
|
|
140
|
-
|
|
141
|
-
const schema: InputSchema = {
|
|
142
|
-
type: 'structured',
|
|
143
|
-
fields: [
|
|
144
|
-
{ name: 'summary', type: 'text', prompt: 'Summary', required: true },
|
|
145
|
-
{ name: 'criteria', type: 'array', items: 'text', prompt: 'Criteria', required: true },
|
|
146
|
-
],
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const result = await collectStructuredInput(schema);
|
|
150
|
-
|
|
151
|
-
expect(result).toEqual({ summary: 'Add dark mode', criteria: ['Must work'] });
|
|
152
|
-
});
|
|
153
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { applyPlaceholders } from '../../src/utils/placeholders.js';
|
|
3
|
-
|
|
4
|
-
describe('applyPlaceholders', () => {
|
|
5
|
-
it('replaces a single known placeholder', () => {
|
|
6
|
-
expect(applyPlaceholders('Hello {{PROJECT_NAME}}', { PROJECT_NAME: 'my-app' }))
|
|
7
|
-
.toBe('Hello my-app');
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
it('replaces multiple placeholders in one pass', () => {
|
|
11
|
-
const result = applyPlaceholders(
|
|
12
|
-
'name: {{PROJECT_NAME}}\ntemplate: {{TEMPLATE_NAME}}\nyear: {{YEAR}}',
|
|
13
|
-
{ PROJECT_NAME: 'x', TEMPLATE_NAME: 'software', YEAR: '2026' }
|
|
14
|
-
);
|
|
15
|
-
expect(result).toBe('name: x\ntemplate: software\nyear: 2026');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('replaces the same placeholder multiple times', () => {
|
|
19
|
-
expect(applyPlaceholders('{{PROJECT_NAME}} / {{PROJECT_NAME}}', { PROJECT_NAME: 'app' }))
|
|
20
|
-
.toBe('app / app');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('throws on unresolved placeholder', () => {
|
|
24
|
-
expect(() => applyPlaceholders('{{UNKNOWN}}', {}))
|
|
25
|
-
.toThrow('Unresolved placeholder: {{UNKNOWN}}');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('returns content unchanged when no placeholders', () => {
|
|
29
|
-
expect(applyPlaceholders('no placeholders here', {})).toBe('no placeholders here');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('does not replace lowercase or mixed-case patterns', () => {
|
|
33
|
-
// Only {{ALL_CAPS_WITH_UNDERSCORES}} are treated as placeholders
|
|
34
|
-
expect(applyPlaceholders('{{lowercase}}', {})).toBe('{{lowercase}}');
|
|
35
|
-
});
|
|
36
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ES2022",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"declarationMap": true,
|
|
10
|
-
"sourceMap": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"esModuleInterop": true,
|
|
13
|
-
"skipLibCheck": true,
|
|
14
|
-
"forceConsistentCasingInFileNames": true,
|
|
15
|
-
"resolveJsonModule": true,
|
|
16
|
-
"isolatedModules": true,
|
|
17
|
-
"noUnusedLocals": true,
|
|
18
|
-
"noUnusedParameters": true,
|
|
19
|
-
"noImplicitReturns": true,
|
|
20
|
-
"noFallthroughCasesInSwitch": true
|
|
21
|
-
},
|
|
22
|
-
"include": ["src/**/*"],
|
|
23
|
-
"exclude": ["node_modules", "dist", "tests"]
|
|
24
|
-
}
|
package/vitest.config.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vitest/config';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
4
|
-
|
|
5
|
-
// Use a stub only when @studio/runner has not been built (e.g. a fresh git worktree).
|
|
6
|
-
// When dist/ exists (CI, main checkout) the real package is used so that transitive
|
|
7
|
-
// imports from other packages (e.g. @studio/api) continue to resolve correctly.
|
|
8
|
-
const runnerDist = resolve(import.meta.dirname, '../runner/dist/index.js');
|
|
9
|
-
const runnerAlias = existsSync(runnerDist) ? {} : {
|
|
10
|
-
'@studio-foundation/runner': resolve(import.meta.dirname, 'tests/__stubs__/studio-runner.ts'),
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export default defineConfig({
|
|
14
|
-
resolve: {
|
|
15
|
-
alias: runnerAlias,
|
|
16
|
-
},
|
|
17
|
-
test: {
|
|
18
|
-
include: ['tests/**/*.test.ts'],
|
|
19
|
-
},
|
|
20
|
-
});
|