@lhi/n8m 0.2.3 → 0.3.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.
package/README.md CHANGED
@@ -198,15 +198,18 @@ Two ways to create a fixture:
198
198
  # Pull real execution data from n8n (no test run required)
199
199
  n8m fixture capture <workflowId>
200
200
 
201
+ # Browse local files + remote instance interactively
202
+ n8m fixture capture
203
+
201
204
  # Scaffold an empty template to fill in by hand
202
205
  n8m fixture init <workflowId>
203
206
  ```
204
207
 
205
- **`capture`** connects to your n8n instance, fetches the 25 most recent
206
- executions for the workflow, and presents an interactive menu to pick which one
207
- to save as a fixture no tests run. Use this when you have a workflow that
208
- already ran successfully in n8n and you want to lock in that execution data for
209
- offline testing going forward.
208
+ **`capture`** connects to your n8n instance, fetches the most recent executions
209
+ for the workflow, and presents an interactive menu to pick which one to save.
210
+ You'll be prompted for a fixture name (e.g. `happy-path`, `missing-field`) and
211
+ expected outcome (`pass` or `fail`). Fixtures are saved to
212
+ `.n8m/fixtures/<workflowId>/<name>.json`.
210
213
 
211
214
  ```bash
212
215
  n8m fixture capture abc123
@@ -215,12 +218,21 @@ n8m fixture capture abc123
215
218
  # → #177916 success 3/4/2026, 10:48:47 AM
216
219
  # → #177914 success 3/4/2026, 10:48:23 AM
217
220
  # → ❯ #177913 error 3/4/2026, 10:47:59 AM
218
- # → Selected execution 177913
219
- # → Fixture saved to .n8m/fixtures/abc123.json
221
+ # → Name this fixture (e.g. happy-path, missing-field, bad-auth): error-case
222
+ # → Expected test outcome: fail
223
+ # → Fixture saved to .n8m/fixtures/abc123/error-case.json
220
224
  # → Workflow: My Workflow
221
225
  # → Execution: error · 5 node(s) captured
222
226
  ```
223
227
 
228
+ Multiple named fixtures per workflow let you test different scenarios (happy
229
+ path, edge cases, error handling) with one command:
230
+
231
+ ```bash
232
+ n8m test --fixture .n8m/fixtures/abc123 # run ALL fixtures for a workflow
233
+ n8m test --fixture .n8m/fixtures/abc123/error-case.json # run one specific fixture
234
+ ```
235
+
224
236
  **`init`** creates an empty template when you want to define the fixture data
225
237
  yourself, without needing a live execution first.
226
238
 
@@ -230,6 +242,8 @@ yourself, without needing a live execution first.
230
242
  "version": "1.0",
231
243
  "workflowId": "abc123",
232
244
  "workflowName": "My Workflow",
245
+ "description": "happy-path",
246
+ "expectedOutcome": "pass",
233
247
  "workflow": { "name": "My Workflow", "nodes": [], "connections": {} },
234
248
  "execution": {
235
249
  "status": "success",
@@ -249,7 +263,7 @@ Fill in `execution.data.resultData.runData` with the actual output of each node
249
263
  (keyed by exact node name). Then test against it:
250
264
 
251
265
  ```bash
252
- n8m test --fixture .n8m/fixtures/abc123.json
266
+ n8m test --fixture .n8m/fixtures/abc123/happy-path.json
253
267
  ```
254
268
 
255
269
  Fixture files are project-local (`.n8m/fixtures/`) and should be committed to
@@ -271,6 +285,117 @@ n8m deploy ./workflows/my-flow.json --activate
271
285
 
272
286
  ---
273
287
 
288
+ ### `n8m learn` — Build the pattern library
289
+
290
+ Extract reusable engineering knowledge from validated workflows and store it so
291
+ the AI engineer applies the same proven techniques in future generations.
292
+
293
+ ```bash
294
+ # Interactive: pick a workflow from ./workflows/
295
+ n8m learn
296
+
297
+ # Learn from a specific workflow
298
+ n8m learn ./workflows/my-flow/workflow.json
299
+
300
+ # Batch-generate patterns for every workflow in the directory
301
+ n8m learn --all
302
+
303
+ # Import patterns from a GitHub archive (awesome-n8n style)
304
+ n8m learn --github owner/repo
305
+ n8m learn --github owner/repo@main --github-path patterns/google
306
+ n8m learn --github owner/repo --token ghp_xxx # or set GITHUB_TOKEN env var
307
+ ```
308
+
309
+ **How it works:**
310
+
311
+ - **Local mode**: The AI reads a validated workflow JSON, identifies the
312
+ techniques it demonstrates, extracts critical rules (including gotchas to
313
+ avoid), and writes a `.md` pattern file to `.n8m/patterns/`.
314
+ - **GitHub mode**: Fetches `.md` pattern files from any public GitHub repo via
315
+ the GitHub API. Shows a checkbox menu so you choose exactly which patterns to
316
+ import. Recurses into subdirectories automatically.
317
+
318
+ Patterns are Markdown files with a `<!-- keywords: ... -->` comment. When you
319
+ run `n8m create`, the engineer searches all pattern files and injects any that
320
+ match the workflow's goal into the prompt — teaching it to reproduce proven
321
+ approaches exactly.
322
+
323
+ ```
324
+ .n8m/patterns/ ← your project-local library (user patterns)
325
+ docs/patterns/ ← built-in patterns shipped with n8m
326
+ ```
327
+
328
+ User patterns in `.n8m/patterns/` take priority over built-in patterns. A
329
+ pattern file with the same filename overrides the built-in version, so you can
330
+ customize any default.
331
+
332
+ **Contributing default patterns** (for n8m maintainers):
333
+
334
+ ```bash
335
+ # Generate docs/patterns/ from every workflow in ./workflows/
336
+ npm run generate-patterns
337
+
338
+ # Overwrite any already-existing pattern files
339
+ npm run generate-patterns -- --overwrite
340
+
341
+ # Preview what would be written without touching the filesystem
342
+ npm run generate-patterns -- --dry-run
343
+ ```
344
+
345
+ The script scans `workflows/` recursively, calls the AI on each `workflow.json`,
346
+ and writes the result to `docs/patterns/<slug>.md`. Patterns in `docs/patterns/`
347
+ are included in the npm package and available to all users automatically.
348
+
349
+ **Pattern file format:**
350
+
351
+ ```markdown
352
+ <!-- keywords: bigquery, google bigquery, sql, merge, http request -->
353
+
354
+ # Pattern: BigQuery Operations via HTTP Request
355
+
356
+ ## Critical Rules
357
+ - NEVER use n8n-nodes-base.googleBigQuery — it returns no output for DDL/DML.
358
+ Always use n8n-nodes-base.httpRequest with the BigQuery REST API.
359
+
360
+ ## DDL / DML Queries
361
+ ...
362
+ ```
363
+
364
+ ---
365
+
366
+ ### `n8m mcp` — Launch the MCP server
367
+
368
+ Expose `n8m`'s agentic capabilities as tools to any
369
+ [Model Context Protocol](https://modelcontextprotocol.io/) client (Claude
370
+ Desktop, Cursor, etc.).
371
+
372
+ ```bash
373
+ n8m mcp
374
+ # → Starting n8m MCP Server...
375
+ ```
376
+
377
+ The server runs over stdio and registers two tools:
378
+
379
+ | Tool | Description |
380
+ |---|---|
381
+ | `create_workflow` | Generate an n8n workflow from a natural-language goal |
382
+ | `test_workflow` | Deploy a workflow ephemerally to n8n and validate it |
383
+
384
+ Add it to your MCP client config (e.g. Claude Desktop's `claude_desktop_config.json`):
385
+
386
+ ```json
387
+ {
388
+ "mcpServers": {
389
+ "n8m": {
390
+ "command": "npx",
391
+ "args": ["n8m", "mcp"]
392
+ }
393
+ }
394
+ }
395
+ ```
396
+
397
+ ---
398
+
274
399
  ### `n8m resume` — Resume a paused session
275
400
 
276
401
  The agent can pause mid-run for human review (HITL). Resume it with its thread
@@ -330,8 +455,8 @@ n8m config
330
455
  Developer → n8m create "..."
331
456
 
332
457
 
333
- ┌─────────────┐
334
- │ Architect │ Designs the workflow blueprint
458
+ ┌─────────────┐ .n8m/patterns/ docs/patterns/
459
+ │ Architect │ ◄── RAG: node defs + matched patterns
335
460
  └──────┬──────┘
336
461
 
337
462
 
@@ -345,10 +470,18 @@ Developer → n8m create "..."
345
470
  └──────┬──────┘ └─────────────┘
346
471
  │ passed
347
472
 
348
-
349
473
  ./workflows/<slug>/
350
474
  ├── workflow.json
351
475
  └── README.md (with Mermaid diagram)
476
+
477
+
478
+ Developer → n8m learn <workflow.json>
479
+
480
+
481
+ AI analyzes validated workflow
482
+
483
+
484
+ .n8m/patterns/<slug>.md ← feeds back into Engineer on next create
352
485
  ```
353
486
 
354
487
  - **Local first**: credentials and workflow files live on your machine
@@ -358,6 +491,8 @@ Developer → n8m create "..."
358
491
  - **HITL pauses**: the agent stops for your review before committing
359
492
  - **Bring your own AI**: works with OpenAI, Claude, Gemini, Ollama, or any
360
493
  OpenAI-compatible API
494
+ - **Self-improving**: every validated workflow you `learn` from strengthens
495
+ future generations
361
496
 
362
497
  > **For developers**: See the [Developer Guide](docs/DEVELOPER_GUIDE.md) for a
363
498
  > deep-dive into the agentic graph internals, RAG implementation, how to add new
@@ -405,5 +540,8 @@ npm run dev
405
540
  - [x] Multi-workflow project generation support
406
541
  - [x] Fixture record & replay — offline testing with real execution data
407
542
  - [x] Hand-crafted fixture scaffolding (`n8m fixture init`) with JSON Schema
543
+ - [x] Pattern library — extract & reuse knowledge from validated workflows (`n8m learn`)
544
+ - [x] GitHub pattern archive import (`n8m learn --github owner/repo`)
545
+ - [x] MCP server — expose n8m as tools for Claude Desktop and other MCP clients
408
546
  - [ ] Native n8n canvas integration
409
547
  - [ ] Multi-agent collaboration on a single goal
@@ -157,10 +157,10 @@ export declare const graph: import("@langchain/langgraph").CompiledStateGraph<{
157
157
  maxRevisions: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
158
158
  }, import("@langchain/langgraph").StateDefinition, {
159
159
  architect: {
160
- spec?: undefined;
160
+ spec: any;
161
+ collaborationLog: string[];
161
162
  strategies?: undefined;
162
163
  needsClarification?: undefined;
163
- collaborationLog?: undefined;
164
164
  } | {
165
165
  spec: import("../services/ai.service.js").WorkflowSpec;
166
166
  strategies: {
@@ -197,6 +197,12 @@ export declare const graph: import("@langchain/langgraph").CompiledStateGraph<{
197
197
  validationErrors?: undefined;
198
198
  workflowJson?: undefined;
199
199
  candidates?: undefined;
200
+ } | {
201
+ workflowJson: any;
202
+ revisionCount?: undefined;
203
+ validationStatus?: undefined;
204
+ validationErrors?: undefined;
205
+ candidates?: undefined;
200
206
  } | {
201
207
  candidates: any[];
202
208
  revisionCount?: undefined;
@@ -411,10 +417,10 @@ export declare const runAgenticWorkflow: (goal: string, initialState?: Partial<t
411
417
  */
412
418
  export declare const runAgenticWorkflowStream: (goal: string, threadId?: string) => Promise<import("@langchain/core/utils/stream").IterableReadableStream<{
413
419
  architect?: {
414
- spec?: undefined;
420
+ spec: any;
421
+ collaborationLog: string[];
415
422
  strategies?: undefined;
416
423
  needsClarification?: undefined;
417
- collaborationLog?: undefined;
418
424
  } | {
419
425
  spec: import("../services/ai.service.js").WorkflowSpec;
420
426
  strategies: {
@@ -451,6 +457,12 @@ export declare const runAgenticWorkflowStream: (goal: string, threadId?: string)
451
457
  validationErrors?: undefined;
452
458
  workflowJson?: undefined;
453
459
  candidates?: undefined;
460
+ } | {
461
+ workflowJson: any;
462
+ revisionCount?: undefined;
463
+ validationStatus?: undefined;
464
+ validationErrors?: undefined;
465
+ candidates?: undefined;
454
466
  } | {
455
467
  candidates: any[];
456
468
  revisionCount?: undefined;
@@ -1,9 +1,9 @@
1
1
  import { TeamState } from "../state.js";
2
2
  export declare const architectNode: (state: typeof TeamState.State) => Promise<{
3
- spec?: undefined;
3
+ spec: any;
4
+ collaborationLog: string[];
4
5
  strategies?: undefined;
5
6
  needsClarification?: undefined;
6
- collaborationLog?: undefined;
7
7
  } | {
8
8
  spec: import("../../services/ai.service.js").WorkflowSpec;
9
9
  strategies: {
@@ -10,7 +10,11 @@ export const architectNode = async (state) => {
10
10
  // parallel engineers (via Send) to rebuild the workflow from scratch, which
11
11
  // produces very large JSON that is error-prone and throws away the user's work.
12
12
  if (state.workflowJson) {
13
- return {};
13
+ const plan = await aiService.generateModificationPlan(state.userGoal, state.workflowJson);
14
+ return {
15
+ spec: plan,
16
+ collaborationLog: [`Architect: Modification plan — ${plan.description}`],
17
+ };
14
18
  }
15
19
  try {
16
20
  const spec = await aiService.generateSpec(state.userGoal);
@@ -17,6 +17,12 @@ export declare const engineerNode: (state: typeof TeamState.State) => Promise<{
17
17
  validationErrors?: undefined;
18
18
  workflowJson?: undefined;
19
19
  candidates?: undefined;
20
+ } | {
21
+ workflowJson: any;
22
+ revisionCount?: undefined;
23
+ validationStatus?: undefined;
24
+ validationErrors?: undefined;
25
+ candidates?: undefined;
20
26
  } | {
21
27
  candidates: any[];
22
28
  revisionCount?: undefined;
@@ -12,8 +12,13 @@ export const engineerNode = async (state) => {
12
12
  // Search for relevant nodes (limit 8 to save context)
13
13
  const relevantDefs = nodeService.search(queryText, 8);
14
14
  const staticRef = nodeService.getStaticReference();
15
- const ragContext = (relevantDefs.length > 0 || staticRef)
16
- ? `\n\n[N8N NODE REFERENCE GUIDE]\n${staticRef}\n\n[AVAILABLE NODE SCHEMAS - USE THESE EXACT PARAMETERS]\n${nodeService.formatForLLM(relevantDefs)}`
15
+ // Search pattern library for proven working examples
16
+ const matchedPatterns = nodeService.searchPatterns(queryText);
17
+ const patternsContext = matchedPatterns.length > 0
18
+ ? `\n\n[PROVEN WORKFLOW PATTERNS - FOLLOW THESE EXACTLY]\n${matchedPatterns.join('\n\n---\n\n')}`
19
+ : "";
20
+ const ragContext = (relevantDefs.length > 0 || staticRef || matchedPatterns.length > 0)
21
+ ? `\n\n[N8N NODE REFERENCE GUIDE]\n${staticRef}\n\n[AVAILABLE NODE SCHEMAS - USE THESE EXACT PARAMETERS]\n${nodeService.formatForLLM(relevantDefs)}${patternsContext}`
17
22
  : "";
18
23
  // Self-Correction Loop Check
19
24
  if (state.validationErrors && state.validationErrors.length > 0) {
@@ -57,9 +62,13 @@ export const engineerNode = async (state) => {
57
62
  throw error;
58
63
  }
59
64
  }
60
- // Pass-through if workflow exists and no errors (Initial pass for existing workflow)
65
+ // Modification mode: existing workflow + spec from architect
61
66
  if (state.workflowJson) {
62
- return {};
67
+ if (!state.spec) {
68
+ return {}; // No plan — nothing to do
69
+ }
70
+ const modifiedWorkflow = await aiService.applyModification(state.workflowJson, state.userGoal, state.spec, state.userFeedback, state.availableNodeTypes || []);
71
+ return { workflowJson: modifiedWorkflow };
63
72
  }
64
73
  // Standard Creation Flow
65
74
  // console.log("⚙️ Engineer is building the workflow...");
@@ -88,6 +97,31 @@ export const engineerNode = async (state) => {
88
97
  - Use "n8n-nodes-base.htmlExtract" for HTML/Cheerio extraction.
89
98
  6. Connections Structure: The "connections" object keys MUST BE THE SOURCE NODE NAME. The "node" field inside the connection array MUST BE THE TARGET NODE NAME.
90
99
  7. Connection Nesting: Ensure the correct n8n connection structure: "SourceNodeName": { "main": [ [ { "node": "TargetNodeName", "type": "main", "index": 0 } ] ] }.
100
+ 8. Error Connections: In addition to "main", nodes support an "error" output that fires when a node fails. Use this for error handling and cleanup flows. Example:
101
+ "NodeThatMightFail": {
102
+ "main": [ [ { "node": "NextNode", "type": "main", "index": 0 } ] ],
103
+ "error": [ [ { "node": "CleanupOrErrorHandler", "type": "main", "index": 0 } ] ]
104
+ }
105
+ Any node that could fail mid-workflow AND where partial execution would leave side effects (e.g. temporary DB tables, uploaded files, open transactions) MUST have an error connection to a cleanup node.
106
+ 9. HTTP Request Configuration: The method determines required fields.
107
+ - GET/DELETE: only "url" (and optional "sendQuery"/"sendHeaders") are needed — do NOT include "sendBody".
108
+ - POST/PUT/PATCH: MUST include "sendBody": true AND a "body" object:
109
+ { "method": "POST", "url": "...", "sendBody": true, "specifyBody": "json", "jsonBody": "={{ JSON.stringify($json) }}" }
110
+ - Authentication: use "authentication": "predefinedCredentialType" + "nodeCredentialType": "<CredentialTypeName>" for service credentials.
111
+ - Minimal config: only include fields relevant to the method. Do not add empty optional fields.
112
+ 10. Resource/Operation Nodes (Slack, Google Sheets, Airtable, Gmail, etc.): The "resource" + "operation" pair together determine which parameters are required. Different operations need different fields:
113
+ - post/create operations typically need target identifiers (channel, spreadsheetId, etc.) and content fields.
114
+ - update/patch operations typically need a record ID (messageId, rowId, etc.) and the fields to update.
115
+ - get/list operations typically need filter/search parameters, not content fields.
116
+ Always set both "resource" and "operation" first, then configure only the fields that operation requires.
117
+ 11. Credentials Format: Credential references must follow this structure:
118
+ "credentials": { "<credentialTypeName>": { "id": "CREDENTIAL_ID", "name": "Human Readable Name" } }
119
+ Use the exact credential type name that matches the node (e.g. "slackApi", "googleSheetsOAuth2Api", "googleBigQueryOAuth2Api").
120
+ For Google services, prefer service account credentials over OAuth2 when available:
121
+ - BigQuery: use "googleApi" (service account) instead of "googleBigQueryOAuth2Api"
122
+ - Google Sheets: use "googleSheetsServiceAccountApi" instead of "googleSheetsOAuth2Api"
123
+ - Google Drive: use "googleDriveServiceAccountApi" instead of "googleDriveOAuth2Api"
124
+ - Other Google nodes: check if a service account variant exists (typically named "<serviceName>ServiceAccountApi")
91
125
 
92
126
  Output a JSON object with this structure:
93
127
  {
@@ -114,7 +148,7 @@ export const engineerNode = async (state) => {
114
148
  throw new Error("AI generated invalid JSON for workflow from spec");
115
149
  }
116
150
  if (result.workflows && Array.isArray(result.workflows)) {
117
- result.workflows = result.workflows.map((wf) => aiService.fixHallucinatedNodes(wf));
151
+ result.workflows = result.workflows.map((wf) => aiService.wireOrphanedErrorHandlers(aiService.fixHallucinatedNodes(wf)));
118
152
  }
119
153
  return {
120
154
  // Only push to candidates — the Supervisor sets workflowJson after fan-in.
@@ -10,6 +10,7 @@ import { promptMultiline } from '../utils/multilinePrompt.js';
10
10
  import { DocService } from '../services/doc.service.js';
11
11
  import { ConfigManager } from '../utils/config.js';
12
12
  import { N8nClient } from '../utils/n8nClient.js';
13
+ import { AIService } from '../services/ai.service.js';
13
14
  export default class Create extends Command {
14
15
  static args = {
15
16
  description: Args.string({
@@ -147,6 +148,11 @@ export default class Create extends Command {
147
148
  });
148
149
  }
149
150
  choices.push(new inquirer.Separator());
151
+ choices.push({
152
+ name: 'Discuss details with the Engineer',
153
+ value: { type: 'chat' },
154
+ short: 'Discuss',
155
+ });
150
156
  choices.push({
151
157
  name: 'Add feedback before building',
152
158
  value: { type: 'feedback' },
@@ -171,7 +177,38 @@ export default class Create extends Command {
171
177
  }
172
178
  let chosenSpec = choice.strategy ?? spec;
173
179
  let stateUpdate = { spec: chosenSpec, userFeedback: undefined };
174
- if (choice.type === 'feedback') {
180
+ if (choice.type === 'chat') {
181
+ const aiService = AIService.getInstance();
182
+ const chatHistory = [];
183
+ let currentSpec = chosenSpec ?? strategies[0] ?? spec;
184
+ this.log(theme.header('\nCHATTING WITH THE ENGINEER'));
185
+ this.log(theme.muted(` Plan: ${currentSpec?.suggestedName}`));
186
+ this.log(theme.muted(` Type your question or request. Enter "done" when ready to build.\n`));
187
+ // eslint-disable-next-line no-constant-condition
188
+ while (true) {
189
+ const { message } = await inquirer.prompt([{
190
+ type: 'input',
191
+ name: 'message',
192
+ message: 'You:',
193
+ }]);
194
+ const trimmed = message.trim();
195
+ if (!trimmed || /^(done|build|approve|go|ok|yes)$/i.test(trimmed)) {
196
+ this.log(theme.agent(`Understood. Building "${currentSpec?.suggestedName}"...\n`));
197
+ break;
198
+ }
199
+ const { reply, updatedSpec } = await aiService.chatAboutSpec(currentSpec, chatHistory, trimmed);
200
+ chatHistory.push({ role: 'user', content: trimmed });
201
+ chatHistory.push({ role: 'assistant', content: reply });
202
+ currentSpec = updatedSpec;
203
+ this.log(`\n${theme.agent('Engineer:')} ${reply}\n`);
204
+ if (updatedSpec.suggestedName !== (chosenSpec ?? spec)?.suggestedName) {
205
+ this.log(theme.muted(` (Plan updated: ${updatedSpec.suggestedName})`));
206
+ }
207
+ }
208
+ chosenSpec = currentSpec;
209
+ stateUpdate = { spec: chosenSpec, userFeedback: undefined };
210
+ }
211
+ else if (choice.type === 'feedback') {
175
212
  const { feedback } = await inquirer.prompt([{
176
213
  type: 'input',
177
214
  name: 'feedback',
@@ -184,7 +221,7 @@ export default class Create extends Command {
184
221
  else {
185
222
  this.log(theme.agent(`Building "${chosenSpec?.suggestedName}"...`));
186
223
  }
187
- await graph.updateState({ configurable: { thread_id: threadId } }, stateUpdate, nextNode);
224
+ await graph.updateState({ configurable: { thread_id: threadId } }, stateUpdate);
188
225
  const buildStream = await graph.stream(null, { configurable: { thread_id: threadId } });
189
226
  for await (const event of buildStream) {
190
227
  const n = Object.keys(event)[0];
@@ -258,8 +295,10 @@ export default class Create extends Command {
258
295
  const savedResources = [];
259
296
  const docService = DocService.getInstance();
260
297
  for (const workflow of workflows) {
261
- const projectTitle = await docService.generateProjectTitle(workflow);
262
- workflow.name = projectTitle; // Standardize name
298
+ // Use the workflow's own name (set by the Engineer from the spec's suggestedName).
299
+ // Only call generateProjectTitle as a fallback when the name is missing or generic.
300
+ const projectTitle = workflow.name || await docService.generateProjectTitle(workflow);
301
+ workflow.name = projectTitle;
263
302
  const slug = docService.generateSlug(projectTitle);
264
303
  const workflowsDir = path.join(process.cwd(), 'workflows');
265
304
  const targetDir = path.join(workflowsDir, slug);
@@ -1,13 +1,14 @@
1
1
  import { Command } from '@oclif/core';
2
2
  export default class Deploy extends Command {
3
3
  static args: {
4
- workflow: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
4
+ workflow: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
5
  };
6
6
  static description: string;
7
7
  static examples: string[];
8
8
  static flags: {
9
9
  instance: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
10
  activate: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ dir: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
12
  };
12
13
  run(): Promise<void>;
13
14
  }