@fractary/faber-cli 1.0.0 → 1.2.0

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.
@@ -6,7 +6,7 @@ import * as fs from 'fs/promises';
6
6
  import * as path from 'path';
7
7
  import chalk from 'chalk';
8
8
  export function createInitCommand() {
9
- return new Command('init')
9
+ return new Command('workflow-init')
10
10
  .description('Initialize a new FABER project')
11
11
  .option('--preset <name>', 'Use a preset configuration', 'default')
12
12
  .option('--force', 'Overwrite existing configuration')
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Plan command - FABER CLI planning command
3
+ *
4
+ * Batch workflow planning for GitHub issues
5
+ */
6
+ import { Command } from 'commander';
7
+ /**
8
+ * Create the plan command
9
+ */
10
+ export declare function createPlanCommand(): Command;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/plan/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+CpC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAkB3C"}
@@ -0,0 +1,383 @@
1
+ /**
2
+ * Plan command - FABER CLI planning command
3
+ *
4
+ * Batch workflow planning for GitHub issues
5
+ */
6
+ import { Command } from 'commander';
7
+ import chalk from 'chalk';
8
+ import { AnthropicClient } from '../../lib/anthropic-client.js';
9
+ import { RepoClient } from '../../lib/repo-client.js';
10
+ import { ConfigManager } from '../../lib/config.js';
11
+ import { prompt } from '../../utils/prompt.js';
12
+ import { validateWorkIds, validateLabels, validateWorkflowName, validatePlanId, } from '../../utils/validation.js';
13
+ import fs from 'fs/promises';
14
+ import path from 'path';
15
+ /**
16
+ * Create the plan command
17
+ */
18
+ export function createPlanCommand() {
19
+ return new Command('plan')
20
+ .description('Plan workflows for GitHub issues')
21
+ .option('--work-id <ids>', 'Comma-separated list of work item IDs (e.g., "258,259,260")')
22
+ .option('--work-label <labels>', 'Comma-separated label filters (e.g., "workflow:etl,status:approved")')
23
+ .option('--workflow <name>', 'Override workflow (default: read from issue "workflow:*" label)')
24
+ .option('--no-worktree', 'Skip worktree creation')
25
+ .option('--no-branch', 'Skip branch creation')
26
+ .option('--skip-confirm', 'Skip confirmation prompt (use with caution)')
27
+ .option('--output <format>', 'Output format: text|json|yaml', 'text')
28
+ .option('--json', 'Output as JSON (shorthand for --output json)')
29
+ .action(async (options) => {
30
+ try {
31
+ await executePlanCommand(options);
32
+ }
33
+ catch (error) {
34
+ handlePlanError(error, options);
35
+ }
36
+ });
37
+ }
38
+ /**
39
+ * Main execution logic for plan command
40
+ */
41
+ async function executePlanCommand(options) {
42
+ const outputFormat = options.json ? 'json' : options.output || 'text';
43
+ // Validate arguments
44
+ if (!options.workId && !options.workLabel) {
45
+ throw new Error('Either --work-id or --work-label must be provided');
46
+ }
47
+ if (options.workId && options.workLabel) {
48
+ throw new Error('Cannot use both --work-id and --work-label at the same time');
49
+ }
50
+ // Initialize clients
51
+ const config = await ConfigManager.load();
52
+ const repoClient = new RepoClient(config);
53
+ const anthropicClient = new AnthropicClient(config);
54
+ if (outputFormat === 'text') {
55
+ console.log(chalk.blue('FABER CLI - Workflow Planning'));
56
+ console.log(chalk.gray('═'.repeat(50)));
57
+ }
58
+ // Step 1: Fetch issues from GitHub
59
+ if (outputFormat === 'text') {
60
+ console.log(chalk.cyan('\n→ Fetching issues from GitHub...'));
61
+ }
62
+ let issues;
63
+ try {
64
+ if (options.workId) {
65
+ // Validate work IDs before fetching
66
+ const ids = validateWorkIds(options.workId);
67
+ issues = await repoClient.fetchIssues(ids);
68
+ if (outputFormat === 'text') {
69
+ console.log(chalk.green(` ✓ Fetched ${issues.length} issue(s) by ID`));
70
+ }
71
+ }
72
+ else if (options.workLabel) {
73
+ // Validate labels before searching
74
+ const labels = validateLabels(options.workLabel);
75
+ issues = await repoClient.searchIssues(labels);
76
+ if (outputFormat === 'text') {
77
+ console.log(chalk.green(` ✓ Found ${issues.length} issue(s) matching labels`));
78
+ }
79
+ }
80
+ else {
81
+ throw new Error('No issues to process');
82
+ }
83
+ }
84
+ catch (error) {
85
+ if (error instanceof Error && error.message.includes('not yet implemented')) {
86
+ if (outputFormat === 'text') {
87
+ console.log(chalk.yellow('\n⚠️ fractary-repo commands not yet available'));
88
+ console.log(chalk.gray(' This command requires fractary-repo plugin implementation.'));
89
+ console.log(chalk.gray(' See SPEC-00030-FRACTARY-REPO-ENHANCEMENTS.md'));
90
+ }
91
+ else {
92
+ console.log(JSON.stringify({
93
+ status: 'error',
94
+ error: {
95
+ code: 'DEPENDENCY_NOT_AVAILABLE',
96
+ message: 'fractary-repo commands not yet implemented',
97
+ details: 'See SPEC-00030-FRACTARY-REPO-ENHANCEMENTS.md',
98
+ },
99
+ }, null, 2));
100
+ }
101
+ return;
102
+ }
103
+ throw error;
104
+ }
105
+ if (issues.length === 0) {
106
+ if (outputFormat === 'text') {
107
+ console.log(chalk.yellow('\n⚠️ No issues found'));
108
+ }
109
+ else {
110
+ console.log(JSON.stringify({ status: 'success', issues: [], message: 'No issues found' }, null, 2));
111
+ }
112
+ return;
113
+ }
114
+ // Step 2: Extract workflows from labels or prompt user
115
+ if (outputFormat === 'text') {
116
+ console.log(chalk.cyan('\n→ Identifying workflows...'));
117
+ }
118
+ const availableWorkflows = await loadAvailableWorkflows(config);
119
+ const issuesWithWorkflows = await assignWorkflows(issues, availableWorkflows, options, outputFormat);
120
+ // Step 3: Show confirmation prompt
121
+ if (!options.skipConfirm) {
122
+ const confirmed = await showConfirmationPrompt(issuesWithWorkflows, config, outputFormat);
123
+ if (!confirmed) {
124
+ if (outputFormat === 'text') {
125
+ console.log(chalk.yellow('\n✖ Planning cancelled'));
126
+ }
127
+ else {
128
+ console.log(JSON.stringify({ status: 'cancelled', message: 'User cancelled planning' }, null, 2));
129
+ }
130
+ return;
131
+ }
132
+ }
133
+ // Step 4: Plan each issue
134
+ if (outputFormat === 'text') {
135
+ console.log(chalk.cyan('\n→ Planning workflows...'));
136
+ }
137
+ const results = [];
138
+ for (const issue of issuesWithWorkflows) {
139
+ if (outputFormat === 'text') {
140
+ console.log(chalk.gray(`\n[${results.length + 1}/${issuesWithWorkflows.length}] Issue #${issue.number}: ${issue.title}`));
141
+ }
142
+ try {
143
+ const result = await planSingleIssue(issue, config, repoClient, anthropicClient, options, outputFormat);
144
+ results.push(result);
145
+ }
146
+ catch (error) {
147
+ const errorMessage = error instanceof Error ? error.message : String(error);
148
+ if (outputFormat === 'text') {
149
+ console.log(chalk.red(` ✗ Error: ${errorMessage}`));
150
+ }
151
+ results.push({
152
+ issue,
153
+ planId: '',
154
+ branch: '',
155
+ worktree: '',
156
+ error: errorMessage,
157
+ });
158
+ }
159
+ }
160
+ // Step 5: Output summary
161
+ if (outputFormat === 'json') {
162
+ console.log(JSON.stringify({
163
+ status: 'success',
164
+ total: results.length,
165
+ successful: results.filter(r => !r.error).length,
166
+ failed: results.filter(r => r.error).length,
167
+ results,
168
+ }, null, 2));
169
+ }
170
+ else {
171
+ outputTextSummary(results);
172
+ }
173
+ }
174
+ /**
175
+ * Load available workflow configurations
176
+ */
177
+ async function loadAvailableWorkflows(config) {
178
+ const workflowDir = config.workflow?.config_path || './plugins/faber/config/workflows';
179
+ try {
180
+ const files = await fs.readdir(workflowDir);
181
+ return files
182
+ .filter(f => f.endsWith('.json'))
183
+ .map(f => path.basename(f, '.json'));
184
+ }
185
+ catch (error) {
186
+ // Default workflows if directory doesn't exist
187
+ return ['core', 'etl', 'bugfix', 'feature'];
188
+ }
189
+ }
190
+ /**
191
+ * Assign workflows to issues (extract from labels or prompt user)
192
+ */
193
+ async function assignWorkflows(issues, availableWorkflows, options, outputFormat) {
194
+ const issuesWithWorkflows = [];
195
+ for (const issue of issues) {
196
+ let workflow = options.workflow; // Command-line override
197
+ // Validate workflow override if provided
198
+ if (workflow) {
199
+ validateWorkflowName(workflow);
200
+ }
201
+ if (!workflow) {
202
+ // Extract from issue labels
203
+ const workflowLabel = issue.labels.find(label => label.startsWith('workflow:'));
204
+ if (workflowLabel) {
205
+ workflow = workflowLabel.replace('workflow:', '');
206
+ // Validate extracted workflow name
207
+ validateWorkflowName(workflow);
208
+ }
209
+ }
210
+ if (!workflow) {
211
+ // Prompt user
212
+ if (outputFormat === 'text') {
213
+ console.log(chalk.yellow(`\n⚠️ Issue #${issue.number} is missing a workflow label:`));
214
+ console.log(chalk.gray(` ${issue.title}`));
215
+ console.log(chalk.gray(` Available workflows: ${availableWorkflows.join(', ')}`));
216
+ workflow = await prompt(` Select workflow for this issue [${availableWorkflows[0]}]: `);
217
+ if (!workflow) {
218
+ workflow = availableWorkflows[0];
219
+ }
220
+ if (!availableWorkflows.includes(workflow)) {
221
+ throw new Error(`Invalid workflow: ${workflow}. Available: ${availableWorkflows.join(', ')}`);
222
+ }
223
+ }
224
+ else {
225
+ throw new Error(`Issue #${issue.number} is missing workflow label and interactive prompts are disabled in JSON mode`);
226
+ }
227
+ }
228
+ issuesWithWorkflows.push({ ...issue, workflow });
229
+ }
230
+ if (outputFormat === 'text') {
231
+ console.log(chalk.green(` ✓ All issues have workflows assigned`));
232
+ }
233
+ return issuesWithWorkflows;
234
+ }
235
+ /**
236
+ * Show confirmation prompt before planning
237
+ */
238
+ async function showConfirmationPrompt(issues, config, outputFormat) {
239
+ if (outputFormat !== 'text') {
240
+ return true; // Skip in JSON mode
241
+ }
242
+ console.log(chalk.cyan('\n📋 Will plan workflows for the following issues:\n'));
243
+ for (const issue of issues) {
244
+ const { organization, project } = getRepoInfoFromConfig(config);
245
+ const branch = `feature/${issue.number}`;
246
+ const worktree = `~/.claude-worktrees/${organization}-${project}-${issue.number}`;
247
+ console.log(chalk.bold(`#${issue.number}: ${issue.title}`));
248
+ console.log(chalk.gray(` Workflow: ${issue.workflow}`));
249
+ console.log(chalk.gray(` Branch: ${branch}`));
250
+ console.log(chalk.gray(` Worktree: ${worktree}`));
251
+ console.log();
252
+ }
253
+ const response = await prompt('Proceed? [Y/n]: ');
254
+ return !response || response.toLowerCase() === 'y' || response.toLowerCase() === 'yes';
255
+ }
256
+ /**
257
+ * Plan a single issue
258
+ */
259
+ async function planSingleIssue(issue, config, repoClient, anthropicClient, options, outputFormat) {
260
+ const { organization, project } = getRepoInfoFromConfig(config);
261
+ const branch = `feature/${issue.number}`;
262
+ const worktree = `~/.claude-worktrees/${organization}-${project}-${issue.number}`;
263
+ // Generate plan via Anthropic API
264
+ if (outputFormat === 'text') {
265
+ console.log(chalk.gray(' → Generating plan...'));
266
+ }
267
+ const plan = await anthropicClient.generatePlan({
268
+ workflow: issue.workflow,
269
+ issueTitle: issue.title,
270
+ issueDescription: issue.description,
271
+ issueNumber: issue.number,
272
+ });
273
+ const planId = plan.plan_id;
274
+ // Create branch
275
+ if (!options.noBranch) {
276
+ if (outputFormat === 'text') {
277
+ console.log(chalk.gray(` → Creating branch: ${branch}...`));
278
+ }
279
+ await repoClient.createBranch(branch);
280
+ }
281
+ // Create worktree
282
+ let worktreePath = worktree;
283
+ if (!options.noWorktree) {
284
+ if (outputFormat === 'text') {
285
+ console.log(chalk.gray(` → Creating worktree: ${worktree}...`));
286
+ }
287
+ const worktreeResult = await repoClient.createWorktree({
288
+ workId: issue.number.toString(),
289
+ path: worktree,
290
+ });
291
+ worktreePath = worktreeResult.absolute_path;
292
+ }
293
+ // Write plan to worktree
294
+ if (!options.noWorktree) {
295
+ // Validate plan ID format (prevent path traversal via malicious plan IDs)
296
+ validatePlanId(planId);
297
+ const planDir = path.join(worktreePath, '.fractary', 'plans');
298
+ await fs.mkdir(planDir, { recursive: true });
299
+ // Construct and validate path
300
+ const planPath = path.join(planDir, `${planId}.json`);
301
+ // Note: path.join automatically normalizes and prevents basic traversal,
302
+ // but we validate the plan ID format as an additional layer of defense
303
+ await fs.writeFile(planPath, JSON.stringify(plan, null, 2));
304
+ if (outputFormat === 'text') {
305
+ console.log(chalk.gray(` → Plan written to ${planPath}`));
306
+ }
307
+ }
308
+ // Update GitHub issue with plan_id
309
+ if (outputFormat === 'text') {
310
+ console.log(chalk.gray(` → Updating GitHub issue...`));
311
+ }
312
+ await repoClient.updateIssue({
313
+ id: issue.number.toString(),
314
+ comment: `🤖 Workflow plan created: ${planId}`,
315
+ addLabel: 'faber:planned',
316
+ });
317
+ if (outputFormat === 'text') {
318
+ console.log(chalk.green(` ✓ Plan: ${planId}`));
319
+ }
320
+ return {
321
+ issue,
322
+ planId,
323
+ branch,
324
+ worktree: worktreePath,
325
+ };
326
+ }
327
+ /**
328
+ * Get repository info from config
329
+ */
330
+ function getRepoInfoFromConfig(config) {
331
+ return {
332
+ organization: config.github?.organization || 'unknown',
333
+ project: config.github?.project || 'unknown',
334
+ };
335
+ }
336
+ /**
337
+ * Output text summary
338
+ */
339
+ function outputTextSummary(results) {
340
+ console.log(chalk.cyan('\n' + '═'.repeat(50)));
341
+ const successful = results.filter(r => !r.error);
342
+ const failed = results.filter(r => r.error);
343
+ if (successful.length > 0) {
344
+ console.log(chalk.green(`\n✓ Planned ${successful.length} workflow(s) successfully:\n`));
345
+ successful.forEach((result, index) => {
346
+ console.log(chalk.bold(`[${index + 1}/${successful.length}] Issue #${result.issue.number}: ${result.issue.title}`));
347
+ console.log(chalk.gray(` Workflow: ${result.issue.workflow}`));
348
+ console.log(chalk.gray(` Plan: ${result.planId}`));
349
+ console.log(chalk.gray(` Branch: ${result.branch}`));
350
+ console.log(chalk.gray(` Worktree: ${result.worktree}`));
351
+ console.log();
352
+ console.log(chalk.cyan(' To execute:'));
353
+ console.log(chalk.gray(` cd ${result.worktree} && claude`));
354
+ console.log(chalk.gray(` /fractary-faber:workflow-run ${result.issue.number}`));
355
+ console.log();
356
+ });
357
+ }
358
+ if (failed.length > 0) {
359
+ console.log(chalk.red(`\n✗ Failed to plan ${failed.length} workflow(s):\n`));
360
+ failed.forEach((result, index) => {
361
+ console.log(chalk.bold(`[${index + 1}/${failed.length}] Issue #${result.issue.number}: ${result.issue.title}`));
362
+ console.log(chalk.red(` Error: ${result.error}`));
363
+ console.log();
364
+ });
365
+ }
366
+ }
367
+ /**
368
+ * Error handling
369
+ */
370
+ function handlePlanError(error, options) {
371
+ const message = error instanceof Error ? error.message : String(error);
372
+ const outputFormat = options.json ? 'json' : options.output || 'text';
373
+ if (outputFormat === 'json') {
374
+ console.error(JSON.stringify({
375
+ status: 'error',
376
+ error: { code: 'PLAN_ERROR', message },
377
+ }));
378
+ }
379
+ else {
380
+ console.error(chalk.red('Error:'), message);
381
+ }
382
+ process.exit(1);
383
+ }
@@ -1,31 +1,31 @@
1
1
  /**
2
2
  * Workflow commands - FABER workflow execution
3
3
  *
4
- * Provides run, status, resume, pause commands via FaberWorkflow SDK.
4
+ * Provides workflow-run, workflow-status, workflow-resume, workflow-pause commands via FaberWorkflow SDK.
5
5
  */
6
6
  import { Command } from 'commander';
7
7
  /**
8
- * Create the run command
8
+ * Create the workflow-run command
9
9
  */
10
10
  export declare function createRunCommand(): Command;
11
11
  /**
12
- * Create the status command
12
+ * Create the workflow-status command
13
13
  */
14
14
  export declare function createStatusCommand(): Command;
15
15
  /**
16
- * Create the resume command
16
+ * Create the workflow-resume command
17
17
  */
18
18
  export declare function createResumeCommand(): Command;
19
19
  /**
20
- * Create the pause command
20
+ * Create the workflow-pause command
21
21
  */
22
22
  export declare function createPauseCommand(): Command;
23
23
  /**
24
- * Create the recover command
24
+ * Create the workflow-recover command
25
25
  */
26
26
  export declare function createRecoverCommand(): Command;
27
27
  /**
28
- * Create the cleanup command
28
+ * Create the workflow-cleanup command
29
29
  */
30
30
  export declare function createCleanupCommand(): Command;
31
31
  //# sourceMappingURL=index.d.ts.map
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * Workflow commands - FABER workflow execution
3
3
  *
4
- * Provides run, status, resume, pause commands via FaberWorkflow SDK.
4
+ * Provides workflow-run, workflow-status, workflow-resume, workflow-pause commands via FaberWorkflow SDK.
5
5
  */
6
6
  import { Command } from 'commander';
7
7
  import chalk from 'chalk';
8
8
  import { FaberWorkflow, StateManager } from '@fractary/faber';
9
9
  import { parsePositiveInteger } from '../../utils/validation.js';
10
10
  /**
11
- * Create the run command
11
+ * Create the workflow-run command
12
12
  */
13
13
  export function createRunCommand() {
14
- return new Command('run')
14
+ return new Command('workflow-run')
15
15
  .description('Run FABER workflow')
16
16
  .requiredOption('--work-id <id>', 'Work item ID to process')
17
17
  .option('--autonomy <level>', 'Autonomy level: supervised|assisted|autonomous', 'supervised')
@@ -60,10 +60,10 @@ export function createRunCommand() {
60
60
  });
61
61
  }
62
62
  /**
63
- * Create the status command
63
+ * Create the workflow-status command
64
64
  */
65
65
  export function createStatusCommand() {
66
- return new Command('status')
66
+ return new Command('workflow-status')
67
67
  .description('Show workflow status')
68
68
  .option('--work-id <id>', 'Work item ID to check')
69
69
  .option('--workflow-id <id>', 'Workflow ID to check')
@@ -75,7 +75,7 @@ export function createStatusCommand() {
75
75
  if (options.workflowId) {
76
76
  // Status for specific workflow by ID
77
77
  const workflow = new FaberWorkflow();
78
- const status = workflow.getStatus(options.workflowId);
78
+ const status = workflow.status.get(options.workflowId);
79
79
  if (options.json) {
80
80
  console.log(JSON.stringify({ status: 'success', data: status }, null, 2));
81
81
  }
@@ -87,7 +87,7 @@ export function createStatusCommand() {
87
87
  }
88
88
  else if (options.workId) {
89
89
  // Status for work item's active workflow
90
- const state = stateManager.getActiveWorkflow(options.workId);
90
+ const state = stateManager.workflow.getActive(options.workId);
91
91
  if (!state) {
92
92
  if (options.json) {
93
93
  console.log(JSON.stringify({
@@ -123,7 +123,7 @@ export function createStatusCommand() {
123
123
  }
124
124
  else {
125
125
  // List all workflows
126
- const workflows = stateManager.listWorkflows();
126
+ const workflows = stateManager.workflow.list();
127
127
  if (options.json) {
128
128
  console.log(JSON.stringify({ status: 'success', data: workflows }, null, 2));
129
129
  }
@@ -147,10 +147,10 @@ export function createStatusCommand() {
147
147
  });
148
148
  }
149
149
  /**
150
- * Create the resume command
150
+ * Create the workflow-resume command
151
151
  */
152
152
  export function createResumeCommand() {
153
- return new Command('resume')
153
+ return new Command('workflow-resume')
154
154
  .description('Resume a paused workflow')
155
155
  .argument('<workflow_id>', 'Workflow ID to resume')
156
156
  .option('--json', 'Output as JSON')
@@ -175,10 +175,10 @@ export function createResumeCommand() {
175
175
  });
176
176
  }
177
177
  /**
178
- * Create the pause command
178
+ * Create the workflow-pause command
179
179
  */
180
180
  export function createPauseCommand() {
181
- return new Command('pause')
181
+ return new Command('workflow-pause')
182
182
  .description('Pause a running workflow')
183
183
  .argument('<workflow_id>', 'Workflow ID to pause')
184
184
  .option('--json', 'Output as JSON')
@@ -199,10 +199,10 @@ export function createPauseCommand() {
199
199
  });
200
200
  }
201
201
  /**
202
- * Create the recover command
202
+ * Create the workflow-recover command
203
203
  */
204
204
  export function createRecoverCommand() {
205
- return new Command('recover')
205
+ return new Command('workflow-recover')
206
206
  .description('Recover a workflow from checkpoint')
207
207
  .argument('<workflow_id>', 'Workflow ID to recover')
208
208
  .option('--checkpoint <id>', 'Specific checkpoint ID to recover from')
@@ -211,7 +211,7 @@ export function createRecoverCommand() {
211
211
  .action(async (workflowId, options) => {
212
212
  try {
213
213
  const stateManager = new StateManager();
214
- const state = stateManager.recoverWorkflow(workflowId, {
214
+ const state = stateManager.workflow.recover(workflowId, {
215
215
  checkpointId: options.checkpoint,
216
216
  fromPhase: options.phase,
217
217
  });
@@ -230,10 +230,10 @@ export function createRecoverCommand() {
230
230
  });
231
231
  }
232
232
  /**
233
- * Create the cleanup command
233
+ * Create the workflow-cleanup command
234
234
  */
235
235
  export function createCleanupCommand() {
236
- return new Command('cleanup')
236
+ return new Command('workflow-cleanup')
237
237
  .description('Clean up old workflow states')
238
238
  .option('--max-age <days>', 'Delete workflows older than N days', '30')
239
239
  .option('--json', 'Output as JSON')
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CA0CxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CA2IxC"}