@mintlify/cli 4.0.1122 → 4.0.1123

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/src/workflow.tsx DELETED
@@ -1,191 +0,0 @@
1
- import { select, input, editor } from '@inquirer/prompts';
2
- import { addLog, addLogs, SuccessLog } from '@mintlify/previewing';
3
- import fse from 'fs-extra';
4
- import { Text } from 'ink';
5
- import path from 'path';
6
-
7
- import { CMD_EXEC_PATH, isAI } from './helpers.js';
8
-
9
- export function slugify(name: string): string {
10
- return name
11
- .toLowerCase()
12
- .replace(/[^a-z0-9]+/g, '-')
13
- .replace(/^-|-$/g, '');
14
- }
15
-
16
- const CRON_FIELD = /^(\*|(\*\/\d+)|(\d+(-\d+)?(,\d+(-\d+)?)*))$/;
17
-
18
- export function isValidCron(expr: string): boolean {
19
- const fields = expr.trim().split(/\s+/);
20
- if (fields.length !== 5) return false;
21
- return fields.every((f) => CRON_FIELD.test(f));
22
- }
23
-
24
- function escapeYaml(value: string): string {
25
- return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
26
- }
27
-
28
- export function buildFrontmatter(config: {
29
- name: string;
30
- triggerType: string;
31
- cronExpression?: string;
32
- triggerRepos?: string[];
33
- contextRepos?: string[];
34
- automerge: boolean;
35
- }): string {
36
- const lines: string[] = [];
37
- lines.push(`name: "${escapeYaml(config.name)}"`);
38
-
39
- if (config.triggerType === 'push') {
40
- lines.push('on:');
41
- lines.push(' push:');
42
- if (config.triggerRepos) {
43
- for (const repo of config.triggerRepos) {
44
- lines.push(` - repo: "${escapeYaml(repo)}"`);
45
- }
46
- }
47
- } else {
48
- lines.push('on:');
49
- lines.push(` cron: "${escapeYaml(config.cronExpression ?? '')}"`);
50
- }
51
-
52
- if (config.contextRepos && config.contextRepos.length > 0) {
53
- lines.push('context:');
54
- for (const repo of config.contextRepos) {
55
- lines.push(` - repo: "${escapeYaml(repo)}"`);
56
- }
57
- }
58
-
59
- if (config.automerge) {
60
- lines.push('automerge: true');
61
- }
62
-
63
- return `---\n${lines.join('\n')}\n---`;
64
- }
65
-
66
- const sendUsageMessageForAI = () => {
67
- addLogs(
68
- <Text>Agent Detected - sending AI friendly prompt</Text>,
69
- <Text>{'<system-message>'}</Text>,
70
- <Text>
71
- Example usage of `mintlify workflow`. This command is interactive and creates a workflow file
72
- in `.mintlify/workflows/`.
73
- </Text>,
74
- <Text>
75
- Workflow files are Markdown files with YAML frontmatter. Instead of running this command, you
76
- can directly create a `.mintlify/workflows/your-workflow.md` file.
77
- </Text>,
78
- <Text>
79
- Frontmatter fields: name (string), on.cron (string) or on.push with repo list, context (array
80
- of objects with repo key), automerge (boolean, only when true).
81
- </Text>,
82
- <Text>The Markdown body contains the agent instructions/prompt.</Text>,
83
- <Text>{'</system-message>'}</Text>
84
- );
85
- };
86
-
87
- export async function addWorkflow(): Promise<void> {
88
- const docsJsonPath = path.join(CMD_EXEC_PATH, 'docs.json');
89
- if (!(await fse.pathExists(docsJsonPath))) {
90
- throw new Error(
91
- 'docs.json not found in the current directory. Please run this command from your docs repository root.'
92
- );
93
- }
94
-
95
- if (isAI()) {
96
- sendUsageMessageForAI();
97
- return;
98
- }
99
-
100
- const workflowName = await input({
101
- message: 'Workflow name',
102
- default: 'Update changelog',
103
- });
104
-
105
- if (!workflowName.trim()) {
106
- throw new Error('Workflow name cannot be empty.');
107
- }
108
-
109
- const slug = slugify(workflowName);
110
- if (!slug) {
111
- throw new Error('Workflow name must contain at least one alphanumeric character.');
112
- }
113
-
114
- const triggerType = await select({
115
- message: 'Trigger type',
116
- choices: [
117
- { name: 'Cron (scheduled)', value: 'cron' },
118
- { name: 'Push (on push to repo)', value: 'push' },
119
- ],
120
- });
121
-
122
- let cronExpression: string | undefined;
123
- let triggerRepos: string[] = [];
124
-
125
- if (triggerType === 'cron') {
126
- cronExpression = await input({
127
- message: 'Cron expression',
128
- default: '0 9 * * 1',
129
- validate: (value) =>
130
- isValidCron(value) ||
131
- 'Invalid cron expression. Expected 5 fields: minute hour day-of-month month day-of-week (e.g. 0 9 * * 1).',
132
- });
133
- } else {
134
- const triggerReposInput = await input({
135
- message: 'Trigger repos (comma-separated, e.g. your-org/your-docs)',
136
- default: '',
137
- });
138
- triggerRepos = triggerReposInput
139
- .split(',')
140
- .map((r) => r.trim())
141
- .filter(Boolean);
142
- }
143
-
144
- const contextReposInput = await input({
145
- message: 'Context repos (comma-separated, e.g. your-org/your-product, optional)',
146
- default: '',
147
- });
148
- const contextRepos = contextReposInput
149
- .split(',')
150
- .map((r) => r.trim())
151
- .filter(Boolean);
152
-
153
- const automergeChoice = await select({
154
- message: 'Enable automerge?',
155
- choices: [
156
- { name: 'Yes', value: 'yes' },
157
- { name: 'No', value: 'no' },
158
- ],
159
- });
160
-
161
- const instructions = await editor({
162
- message: 'Agent instructions (opens your default editor)',
163
- default:
164
- '# Agent Instructions\n\nDescribe what this workflow should do.\n\nFor example:\n- Update the changelog based on recent commits\n- Summarize recent PRs\n',
165
- });
166
-
167
- const frontmatter = buildFrontmatter({
168
- name: workflowName,
169
- triggerType,
170
- cronExpression,
171
- triggerRepos,
172
- contextRepos: contextRepos.length > 0 ? contextRepos : undefined,
173
- automerge: automergeChoice === 'yes',
174
- });
175
-
176
- const filename = slug + '.md';
177
- const workflowDir = path.join(CMD_EXEC_PATH, '.mintlify', 'workflows');
178
- const filePath = path.join(workflowDir, filename);
179
- const relativePath = path.relative(CMD_EXEC_PATH, filePath);
180
-
181
- await fse.ensureDir(workflowDir);
182
-
183
- if (await fse.pathExists(filePath)) {
184
- throw new Error(
185
- `A workflow already exists at ${relativePath}. Please choose a different name or delete the existing file.`
186
- );
187
- }
188
-
189
- await fse.writeFile(filePath, frontmatter + '\n\n' + instructions.trim() + '\n');
190
- addLog(<SuccessLog message={`Workflow created at ${relativePath}`} />);
191
- }