fix: always return minimal n8n output
Build and Push Docker Container / build-and-push (push) Successful in 4m36s

- Node now outputs only stdout (parsed or raw) plus optional stderr

- Keep output stable across all operations to simplify n8n mappings

- Trim trailing newlines from runner stdout/stderr for cleaner display

- Bump server version to 1.0.3 to ship runner/output changes

- Bump n8n node package via versioned build artifacts
This commit is contained in:
2026-06-24 12:04:34 +02:00
parent 3bda4002fe
commit a953214c20
7 changed files with 57 additions and 8 deletions
+2 -2
View File
@@ -36,8 +36,8 @@ async def execute_command(args:list[str], cwd:Path, stdin:str|None, timeout:floa
timed_out = True
duration_ms = int((time.perf_counter() - started) * 1000)
stdout = stdout_b.decode(errors="replace")
stderr = stderr_b.decode(errors="replace")
stdout = stdout_b.decode(errors="replace").rstrip()
stderr = stderr_b.decode(errors="replace").rstrip()
exit_code = process.returncode if process.returncode is not None else -1
if timed_out:
@@ -260,7 +260,16 @@ export class ObsidianApi implements INodeType {
}
const result = await executeObsidianCommand(this, itemIndex, args, { vault, timeout });
returnData.push({ json: result, pairedItem: { item: itemIndex } });
// Always keep n8n output minimal/clean.
// - Prefer parsed stdout (e.g. vault/vaults)
// - Otherwise keep stdout as-is
const stdoutValue = (result as any).parsed_stdout ?? result.stdout;
const out: any = { stdout: stdoutValue };
if (result.stderr) out.stderr = result.stderr;
if (result.timed_out) out.timed_out = result.timed_out;
returnData.push({ json: out, pairedItem: { item: itemIndex } });
} catch (error) {
if (this.continueOnFail()) {
const message = error instanceof Error ? error.message : String(error);
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "n8n-nodes-obsidian-cli-api",
"version": "0.2.1",
"version": "0.2.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "n8n-nodes-obsidian-cli-api",
"version": "0.2.1",
"version": "0.2.2",
"license": "MIT",
"devDependencies": {
"@types/node": "^24.0.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "n8n-nodes-obsidian-cli-api",
"version": "0.2.1",
"version": "0.2.2",
"description": "n8n community nodes for the Obsidian API Docker service backed by the official Obsidian CLI.",
"license": "MIT",
"homepage": "https://git.yiprawr.dev/Docker/obsidian-api",
@@ -14,6 +14,7 @@ export interface ObsidianCommandResult extends IDataObject {
stderr: string;
duration_ms: number;
timed_out: boolean;
parsed_stdout?: IDataObject;
}
export interface ObsidianCredentials extends IDataObject {
@@ -72,6 +73,9 @@ export async function executeObsidianCommand(
}
const result = normalizeCommandResult(response);
const parsed = maybeParseStdout(result);
if (parsed) result.parsed_stdout = parsed;
if (result.exit_code !== 0) {
throw new NodeOperationError(
context.getNode(),
@@ -139,6 +143,42 @@ function extractErrorMessage(body: unknown): string {
return '';
}
function maybeParseStdout(result: ObsidianCommandResult): IDataObject | undefined {
const lastArg = result.command[result.command.length - 1];
if (lastArg !== 'vault' && lastArg !== 'vaults') return undefined;
// Obsidian CLI prints either:
// vault:
// key<TAB>value\nkey<TAB>value\n...
// vaults:
// often one vault per line (names) or a similar tabular output.
const lines = (result.stdout || '')
.split(/\r?\n/)
.map((l) => l.trim())
.filter(Boolean);
if (!lines.length) return undefined;
const isKv = lines.some((l) => l.includes('\t'));
if (!isKv && lastArg === 'vaults') {
return { vaults: lines };
}
const kv: Record<string, string | number> = {};
for (const line of lines) {
const parts = line.split('\t');
if (parts.length < 2) continue;
const key = parts[0].trim();
const rawValue = parts.slice(1).join('\t').trim();
if (!key || !rawValue) continue;
if (/^-?\d+$/.test(rawValue)) kv[key] = Number(rawValue);
else kv[key] = rawValue;
}
return Object.keys(kv).length ? kv : undefined;
}
function normalizeCommandResult(response: unknown): ObsidianCommandResult {
const data = extractResponseBody(response);
const result = typeof data === 'string' ? JSON.parse(data) : data;
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "obsidian-api"
version = "1.0.2"
version = "1.0.3"
description = "HTTP API wrapper for running Obsidian CLI commands from n8n, SDKs, or agent harnesses."
requires-python = ">=3.14"
dependencies = [
Generated
+1 -1
View File
@@ -123,7 +123,7 @@ wheels = [
[[package]]
name = "obsidian-api"
version = "1.0.0"
version = "1.0.3"
source = { virtual = "." }
dependencies = [
{ name = "starlette" },