@n8n-as-code/n8nac 2026.4.0 → 2026.5.0-next.8
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/CHANGELOG.md +6 -0
- package/README.md +4 -4
- package/index.ts +4 -12
- package/package.json +2 -2
- package/skills/n8n-architect/SKILL.md +4 -0
- package/src/workspace.ts +61 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @n8n-as-code/n8nac
|
|
2
2
|
|
|
3
|
+
## [2026.4.1](https://github.com/EtienneLescot/n8n-as-code/compare/@n8n-as-code/n8nac@v2026.4.0...@n8n-as-code/n8nac@v2026.4.1) (2026-03-30)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* make agent workflow testing and sync state resilient ([5850d07](https://github.com/EtienneLescot/n8n-as-code/commit/5850d07d8136ffb24c5106c7391b2d49d4dd2e5d))
|
|
8
|
+
|
|
3
9
|
## [2026.4.0](https://github.com/EtienneLescot/n8n-as-code/compare/@n8n-as-code/n8nac@v2026.3.1...@n8n-as-code/n8nac@v2026.4.0) (2026-03-17)
|
|
4
10
|
|
|
5
11
|
### Features
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Restart the gateway, then run the setup wizard:
|
|
|
23
23
|
openclaw n8nac:setup
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
The wizard asks for your n8n host URL and API key once, saves
|
|
26
|
+
The wizard asks for your n8n host URL and API key once, saves an instance config via
|
|
27
27
|
`n8nac init-auth`, selects your project, and generates an AI context file
|
|
28
28
|
(`AGENTS.md`) in the workspace (`~/.openclaw/n8nac/`).
|
|
29
29
|
|
|
@@ -63,7 +63,7 @@ All files live in `~/.openclaw/n8nac/`:
|
|
|
63
63
|
|
|
64
64
|
```
|
|
65
65
|
~/.openclaw/n8nac/
|
|
66
|
-
n8nac-config.json ←
|
|
66
|
+
n8nac-config.json ← saved instance configs + active selection
|
|
67
67
|
AGENTS.md ← AI context (written by n8nac update-ai)
|
|
68
68
|
workflows/ ← .workflow.ts files (your n8n workflows)
|
|
69
69
|
```
|
|
@@ -119,7 +119,7 @@ openclaw n8nac:setup
|
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
Enter your n8n host and API key when prompted. The wizard writes
|
|
122
|
-
`~/.openclaw/n8nac/n8nac-config.json` and generates `AGENTS.md`.
|
|
122
|
+
`~/.openclaw/n8nac/n8nac-config.json` with the saved instance configs and active selection, then generates `AGENTS.md`.
|
|
123
123
|
|
|
124
124
|
### 4. Iterate on the code
|
|
125
125
|
|
|
@@ -141,7 +141,7 @@ The plugin prefixes all `api.logger` calls with `[n8nac]`.
|
|
|
141
141
|
|
|
142
142
|
```
|
|
143
143
|
~/.openclaw/n8nac/
|
|
144
|
-
n8nac-config.json ←
|
|
144
|
+
n8nac-config.json ← saved instance configs + active selection
|
|
145
145
|
AGENTS.md ← written by update-ai
|
|
146
146
|
workflows/ ← .workflow.ts files
|
|
147
147
|
```
|
package/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { accessSync, constants,
|
|
1
|
+
import { accessSync, constants, mkdirSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
4
4
|
import { registerN8nAcCli } from "./src/cli.js";
|
|
5
5
|
import { createN8nAcTool } from "./src/tool.js";
|
|
6
|
-
import { getWorkspaceDir, isWorkspaceInitialized } from "./src/workspace.js";
|
|
6
|
+
import { getWorkspaceDir, isWorkspaceInitialized, readWorkspaceBinding } from "./src/workspace.js";
|
|
7
7
|
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
9
9
|
// Lightweight prompt context
|
|
@@ -21,17 +21,8 @@ Once you have both, call the \`n8nac\` tool with \`action: "init_auth"\`, then
|
|
|
21
21
|
\`action: "init_project"\` to finish setup.
|
|
22
22
|
`;
|
|
23
23
|
|
|
24
|
-
function readConfig(workspaceDir: string): Record<string, string> {
|
|
25
|
-
try {
|
|
26
|
-
const raw = readFileSync(join(workspaceDir, "n8nac-config.json"), "utf-8");
|
|
27
|
-
return JSON.parse(raw) as Record<string, string>;
|
|
28
|
-
} catch {
|
|
29
|
-
return {};
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
24
|
function buildStatusHeader(workspaceDir: string): string {
|
|
34
|
-
const cfg =
|
|
25
|
+
const cfg = readWorkspaceBinding(workspaceDir);
|
|
35
26
|
const host = cfg.host ?? "(unknown)";
|
|
36
27
|
const project = cfg.projectName ?? cfg.projectId ?? "(unknown)";
|
|
37
28
|
return [
|
|
@@ -40,6 +31,7 @@ function buildStatusHeader(workspaceDir: string): string {
|
|
|
40
31
|
"**The workspace is already fully initialized. Do NOT ask the user for credentials.**",
|
|
41
32
|
"",
|
|
42
33
|
`- Workspace directory: \`${workspaceDir}\``,
|
|
34
|
+
`- Active instance: \`${cfg.activeInstanceName ?? cfg.activeInstanceId ?? "(unknown)"}\``,
|
|
43
35
|
`- n8n host: \`${host}\``,
|
|
44
36
|
`- Active project: \`${project}\``,
|
|
45
37
|
].join("\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@n8n-as-code/n8nac",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.5.0-next.8",
|
|
4
4
|
"description": "OpenClaw plugin for n8n-as-code — create and manage n8n workflows from OpenClaw",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"n8n",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"url": "git+https://github.com/EtienneLescot/n8n-as-code.git",
|
|
16
16
|
"directory": "plugins/openclaw/n8n-as-code"
|
|
17
17
|
},
|
|
18
|
-
"license": "
|
|
18
|
+
"license": "MIT",
|
|
19
19
|
"type": "module",
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "npm run typecheck",
|
|
@@ -20,6 +20,10 @@ Use this skill only for explicit n8n workflow work.
|
|
|
20
20
|
- Use `action: "skills"` whenever you need node search or schema details.
|
|
21
21
|
- Never guess node parameters. The schema lookup is the source of truth.
|
|
22
22
|
- Treat `AGENTS.md` as the authoritative workflow-engineering protocol once this skill is active.
|
|
23
|
+
- When a workflow fails due to missing credentials (Class A), identify the missing credentials clearly and use the documented `n8nac` CLI commands from `AGENTS.md` (for example `npx --yes n8nac workflow credential-required <workflowId> --json`, `npx --yes n8nac credential schema <type>`, `npx --yes n8nac credential create --type <type> --name "<name>" --file cred.json --json`, and `npx --yes n8nac workflow activate <workflowId>`). Do not invent unsupported `n8nac` tool actions or CLI flags; use `--help` if you are unsure.
|
|
24
|
+
- When `n8nac test` reports that a webhook is not registered, treat that as a runtime-state issue first, not as a workflow-code bug. For classic Webhook/Form triggers, the test URL usually requires a manual arm step in the n8n editor (`Execute workflow` or `Listen for test event`). There is no documented public API here to arm test webhooks automatically.
|
|
25
|
+
- When a webhook call succeeds but the workflow still seems broken, inspect the resulting execution with the documented CLI commands from `AGENTS.md` (for example `npx --yes n8nac execution list --workflow-id <workflowId> --limit 5 --json` then `npx --yes n8nac execution get <executionId> --include-data --json`).
|
|
26
|
+
- For GET/HEAD webhooks, prefer `n8nac test --query <json>` when the workflow reads from `$json.query`. Do not invent flags like `--query` unless they are documented in the current `--help`.
|
|
23
27
|
|
|
24
28
|
## Reading workflow files efficiently
|
|
25
29
|
|
package/src/workspace.ts
CHANGED
|
@@ -2,6 +2,15 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
|
|
5
|
+
export type WorkspaceBinding = {
|
|
6
|
+
host?: string;
|
|
7
|
+
projectId?: string;
|
|
8
|
+
projectName?: string;
|
|
9
|
+
syncFolder?: string;
|
|
10
|
+
activeInstanceId?: string;
|
|
11
|
+
activeInstanceName?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
5
14
|
/**
|
|
6
15
|
* Fixed workspace directory for V1.
|
|
7
16
|
* All n8nac files (n8nac-config.json, AGENTS.md, workflows/) live here.
|
|
@@ -10,22 +19,63 @@ export function getWorkspaceDir(): string {
|
|
|
10
19
|
return join(homedir(), ".openclaw", "n8nac");
|
|
11
20
|
}
|
|
12
21
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
function readString(value: unknown): string {
|
|
23
|
+
return typeof value === "string" ? value.trim() : "";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function resolveActiveInstance(config: Record<string, unknown>): Record<string, unknown> | undefined {
|
|
27
|
+
if (!Array.isArray(config.instances)) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const instances = config.instances.filter((value): value is Record<string, unknown> => !!value && typeof value === "object");
|
|
32
|
+
if (!instances.length) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const activeInstanceId = readString(config.activeInstanceId);
|
|
37
|
+
if (activeInstanceId) {
|
|
38
|
+
return instances.find((instance) => readString(instance.id) === activeInstanceId) || instances[0];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return instances[0];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function readWorkspaceBinding(workspaceDir: string): WorkspaceBinding {
|
|
18
45
|
const configPath = join(workspaceDir, "n8nac-config.json");
|
|
19
|
-
if (!existsSync(configPath))
|
|
46
|
+
if (!existsSync(configPath)) {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
20
49
|
|
|
21
50
|
try {
|
|
22
51
|
const raw = readFileSync(configPath, "utf-8");
|
|
23
52
|
const config = JSON.parse(raw) as Record<string, unknown>;
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
53
|
+
const activeInstance = resolveActiveInstance(config);
|
|
54
|
+
const configActiveInstanceId = readString(config.activeInstanceId);
|
|
55
|
+
const resolvedActiveInstanceId = readString(activeInstance?.id);
|
|
56
|
+
const activeInstanceId =
|
|
57
|
+
resolvedActiveInstanceId && resolvedActiveInstanceId === configActiveInstanceId
|
|
58
|
+
? configActiveInstanceId
|
|
59
|
+
: resolvedActiveInstanceId || undefined;
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
host: readString(activeInstance?.host) || readString(config.host) || undefined,
|
|
63
|
+
projectId: readString(activeInstance?.projectId) || readString(config.projectId) || undefined,
|
|
64
|
+
projectName: readString(activeInstance?.projectName) || readString(config.projectName) || undefined,
|
|
65
|
+
syncFolder: readString(activeInstance?.syncFolder) || readString(config.syncFolder) || undefined,
|
|
66
|
+
activeInstanceId,
|
|
67
|
+
activeInstanceName: readString(activeInstance?.name) || undefined,
|
|
68
|
+
};
|
|
28
69
|
} catch {
|
|
29
|
-
return
|
|
70
|
+
return {};
|
|
30
71
|
}
|
|
31
72
|
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Returns true when n8nac has been initialized in the given directory,
|
|
76
|
+
* meaning the config exists and contains a selected project + sync folder.
|
|
77
|
+
*/
|
|
78
|
+
export function isWorkspaceInitialized(workspaceDir: string): boolean {
|
|
79
|
+
const binding = readWorkspaceBinding(workspaceDir);
|
|
80
|
+
return Boolean(binding.projectId && binding.projectName && binding.syncFolder);
|
|
81
|
+
}
|