@com55/node-red-ai-access 0.0.0-stage → 0.1.1

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 ADDED
@@ -0,0 +1,388 @@
1
+ # Changelog
2
+
3
+ All notable changes to Node-RED AI Access will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to
7
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
+
9
+ ## [0.1.1] - 2026-10-17
10
+
11
+ ### Added
12
+
13
+ - `/status` (REST and MCP `get_status`) now includes `openapiJson` in
14
+ `caller.baseUrls` for `rest` tokens, pointing at the served
15
+ `GET /mcp/api/v1/openapi.json`.
16
+ - Optional `aiAccess.corsAllowedOrigins` setting (settings.js): list of browser
17
+ origins allowed to call the AI-facing endpoints cross-origin, with
18
+ `Vary: Origin` and `OPTIONS` preflight support. Origins match
19
+ case-insensitively and the configured canonical origin is echoed; malformed
20
+ origins are rejected. `WWW-Authenticate`, `Retry-After`, and the `RateLimit*`
21
+ headers are exposed to allowed origins.
22
+ - Optional `aiAccess.publicBaseUrl` setting (settings.js) that sets the public
23
+ base URL for absolute links (access-link `url`, proposal `reviewUrl`,
24
+ `accessLinksUrl`), overriding `Host` and `X-Forwarded-*`.
25
+ - The MCP client snippets in the GET-link guide use the public origin
26
+ (`publicBaseUrl`, else the validated request origin) instead of the
27
+ `https://YOUR-NODE-RED` placeholder, which remains only when the origin cannot
28
+ be determined.
29
+
30
+ ### Changed
31
+
32
+ - **Behavior change:** every response on the GET access-link channel
33
+ (`/mcp/a/<token>/*`), including the markdown guide and JSON success and error
34
+ bodies, now defaults to `Content-Type: text/html; charset=utf-8`, because some
35
+ AI web fetchers only read `text/html`. The HTML is a minimal document with the
36
+ same markdown or pretty-printed JSON, fully escaped in one `<pre>`, with safe
37
+ relative `./…` links linkified (no scripts, no external resources). Status
38
+ codes and data are unchanged. The previous representation is returned when
39
+ `Accept` explicitly lists `text/markdown` or `application/json`, or
40
+ `?format=md` / `?format=json` is set; an explicit `Accept: text/plain` returns
41
+ the raw text as `text/plain`. All `/mcp/a/*` responses carry `Vary: Accept`,
42
+ `Cache-Control: no-store`, `Referrer-Policy: no-referrer`,
43
+ `X-Robots-Tag: noindex, nofollow`, and `X-Content-Type-Options: nosniff`; HTML
44
+ adds a restrictive `Content-Security-Policy`. REST and MCP are unchanged.
45
+ - **Behavior change:** the AI-facing endpoints (`/mcp/a/*`, `/mcp/api/*`,
46
+ `/mcp/rpc`) no longer send `Access-Control-Allow-Origin: *` (inherited from
47
+ Node-RED's admin app). No CORS headers are sent unless the request `Origin` is
48
+ listed in `aiAccess.corsAllowedOrigins`. Only browser-based callers are
49
+ affected; server-side clients are not.
50
+ - Attempts to create, list, or revoke access links under a GET access link
51
+ (`/mcp/a/<token>/links`) now return **403** `link_create_not_supported`
52
+ instead of 405. Error registry, `docs/errors.md`, OpenAPI, and get-link docs
53
+ updated.
54
+ - `/status` (GET link, REST, and MCP `get_status`) no longer includes
55
+ `storageDir` for access-link callers; it remains in admin-session responses
56
+ (shown on the `/mcp` page).
57
+
58
+ ### Fixed
59
+
60
+ - Proposal titles no longer repeat the flow name when a long `<title> in <flow>`
61
+ was capped at 80 characters.
62
+ - GET-link HTML no longer linkifies template paths such as `./nodes/<id>`.
63
+
64
+ - **Security:** absolute URLs no longer copy unvalidated `X-Forwarded-Proto` /
65
+ `X-Forwarded-Host` (or `Host`) values. The scheme must be exactly `http` or
66
+ `https` (else the connection scheme is used); hosts must be a DNS name, IPv4,
67
+ or bracketed IPv6 literal with an optional port 1-65535, with no userinfo,
68
+ path, query, fragment, or whitespace. Invalid forwarded hosts fall back to
69
+ `Host`; an invalid `Host` falls back to a relative path.
70
+
71
+ - Absolute URLs (access-link `url`, proposal `reviewUrl`, `accessLinksUrl`) used
72
+ `http://` behind a TLS-terminating proxy. With Express `trust proxy` enabled
73
+ the first `X-Forwarded-Proto` value is now used explicitly; without it, set
74
+ `aiAccess.publicBaseUrl`. Forwarded headers stay ignored when `trust proxy` is
75
+ off.
76
+
77
+ ## [0.1.0] - 2026-10-16
78
+
79
+ First public release of **Node-RED AI Access**: an admin-gated Node-RED 4 plugin
80
+ that lets AI agents read flows and submit reviewable change proposals over REST,
81
+ MCP, and GET access links, with scoped, expiring tokens, a review UI, conflict
82
+ detection, an audit log, and an error-code registry shared by all channels.
83
+ Requires Node.js 20+.
84
+
85
+ ### Release
86
+
87
+ - Initial independent release of **Node-RED AI Access**
88
+ (`@com55/node-red-ai-access`), derived from
89
+ [ziv-daniel/node-red-mcp](https://github.com/ziv-daniel/node-red-mcp).
90
+ - Package metadata, Docker image names, documentation, and CI retargeted to
91
+ `com55/node-red-ai-access`.
92
+ - GitHub Actions CI runs on `ubuntu-latest` for all events.
93
+ - Requires Node.js `>=20`; CI tests Node 20, 22, and 23.
94
+ - `@modelcontextprotocol/sdk` raised to `^1.31.0`.
95
+ - Published package is a minified production build without source maps;
96
+ `prepublishOnly` runs quality checks, tests, and the production build. The
97
+ whole `docs/` folder ships; the OpenAPI spec exists once
98
+ (`docs/api/openapi.yaml`) and is served at `GET /mcp/api/v1/openapi.yaml`.
99
+ - MCP `list_proposals` `status: []` (or `""`) means no status filter; an invalid
100
+ status member returns the same `invalid_filter` message on every channel.
101
+
102
+ ### Fixed (pre-release review)
103
+
104
+ - `RateLimit-*` headers on token requests report the per-token bucket
105
+ (`300;w=60` by default) on every route; requests without a token report the
106
+ per-IP bucket.
107
+ - Spec also served as JSON at `GET /mcp/api/v1/openapi.json`.
108
+ - Proposal responses include `storedTitle` (the title as saved).
109
+ - `duplicate_node_id` checks the whole resulting flows file: the tab id, nodes
110
+ on other tabs, config nodes, and subflows.
111
+ - A single validation error returns its specific message at the top level.
112
+ - Hints come from the error registry on every channel (including
113
+ `node_already_exists` and a top-level `validation_failed` hint); `errors[]`
114
+ entries no longer carry `statusCode`.
115
+ - `status` list filter accepts several values (comma-separated or repeated on
116
+ REST/GET; array or comma string on MCP); any invalid value is
117
+ `invalid_filter`. Repeating a single-value filter is `invalid_filter`.
118
+ - `mine=false` returns only proposals created by other links.
119
+ - GET guide lists every error code, warnings, statuses (including `superseded`),
120
+ and `autoClosedCount`.
121
+
122
+ ### Changed
123
+
124
+ - List filters are validated on GET, REST, and MCP: bad `status`, `limit` (not
125
+ 1–200; no longer clamped), `offset`, or `mine` return **400** `invalid_filter`
126
+ naming the parameter and allowed values. MCP argument schema errors return the
127
+ same JSON body (`invalid_filter` / `invalid_arguments`) instead of raw Zod
128
+ output.
129
+ - List responses on every channel share `total`, `offset`, `limit` (when set),
130
+ `hasMore`, and `nextOffset` (offset-based pagination).
131
+ - Several validation errors in one proposal return **400** `validation_failed`
132
+ (`N validation errors`, all listed in `errors[]`); a single error keeps its
133
+ own code (e.g. **404** `node_not_found`).
134
+ - Out-of-range or non-positive `ttlSeconds` returns **400** `invalid_ttl` with a
135
+ hint stating the per-kind caps (was `access_link_invalid`).
136
+ - `staleOnOlderRev` removed (stale peers are auto-closed on read); responses
137
+ include `autoClosedCount` when a request auto-closed pending proposals.
138
+ - `minutesRemaining` rounds up; `/status` also reports `secondsRemaining`.
139
+ - `token_expired` includes `expiredAt` and `accessLinksUrl`; GET-link 401s
140
+ include `WWW-Authenticate`.
141
+
142
+ ### Added
143
+
144
+ - Duplicate node ids in a full tab or batch are rejected with
145
+ `duplicate_node_id`.
146
+ - Central error-code registry (`src/plugin/error-registry.ts`) generating
147
+ `docs/errors.md`, the GET guide error table, and the OpenAPI `ErrorCode` list
148
+ (`yarn generate:errors`; CI staleness check `yarn check:errors`).
149
+ - Channel onboarding on `/mcp`: REST copies a ready-to-paste AI prompt (base
150
+ URL, Bearer, OpenAPI + discovery, human-approve note, and a stop-and-ask-for-
151
+ GET-link line when custom headers are unavailable); MCP shows a setup panel
152
+ with Claude Desktop / Cursor / VS Code / Claude Code CLI / Streamable HTTP
153
+ tabs (each with its own copy button); GET link still copies the URL. Docs:
154
+ `docs/README.md`, `docs/mcp-clients.md`, `docs/errors.md`, generated
155
+ `docs/mcp-tools.md` (`yarn generate:mcp-tools` / CI stale check).
156
+ - Access-link TTL UX: `/mcp` expiry dropdown (15m / 1h / 4h / 24h / 7d /
157
+ Custom); `get_link` capped at 24h (7d hidden; switching to GET link with
158
+ expiry above 24h — including Custom — resets to 1 hour with a short note);
159
+ `rest` / `mcp` capped at 30d with a red warning above 24h. Server enforces the
160
+ same caps. Status for access-link callers includes `expiresAt` and
161
+ `minutesRemaining`. Known-expired tokens return **401** `token_expired`
162
+ (distinct from `access_link_invalid`).
163
+ - Auto-close stale pending proposals: `expired` (live rev moved) and
164
+ `superseded` (another proposal on the same flow was approved).
165
+ - Conflict trim: `conflictingProposals` lists same-rev or overlapping peers
166
+ only; other older-rev peers appear as `staleOnOlderRev` count. List items omit
167
+ `conflictingProposals`.
168
+ - GET withdraw requires `confirm=1` (prefetch-safe).
169
+ - Proposal list pagination and filters on GET/REST/MCP: `status`, `flowId`,
170
+ `limit`/`offset` (response `total`; max limit 200). MCP tool renamed to
171
+ `list_proposals` (`list_my_proposals` kept as alias).
172
+ - Proposal visibility: every access-link token can list/read **all** proposals
173
+ with `mine: true|false`; filter with `?mine=true` / MCP `list_proposals`
174
+ `{ mine: true }`.
175
+ - Cross-token conflict warnings on submit/read: `conflictingProposals` with
176
+ optional `overlappingNodeIds` / `overlappingFields` (replaces private
177
+ `otherLinkSiblingCount`).
178
+ - Withdraw own pending proposals (`withdrawn` status): GET
179
+ `…/proposals/<id>/withdraw?confirm=1`, REST `POST /proposals/{id}/withdraw`,
180
+ MCP `withdraw_proposal` (+ `/mcp` pill + audit `proposal.withdrawn`).
181
+ - Docs: Known issues (per-token rate limits stack), 1.5MB cap on every channel,
182
+ canonical REST/MCP `payload.nodes` op shapes.
183
+ - Phase 2C: GET `/mcp/a/<token>` cannot mint tokens — explicit **405**
184
+ `link_create_not_supported` on `/mcp/a/<token>/links`; OpenAPI documents
185
+ `AccessLinkKind`, `CreateLinkRequest.kind`, `wrong_token_kind` /
186
+ `invalid_link_kind`, and that get-link has no create-link operation; discovery
187
+ advertises admin-only `POST /links` mint and `getLink.canMintTokens: false`.
188
+
189
+ ### Fixed
190
+
191
+ - Access-link rate limits share one per-token bucket across GET
192
+ `/mcp/a/<token>`, REST Bearer, and MCP (same limiter instances + unified token
193
+ key).
194
+ - Layered-read JSON responses always set `X-Content-Type-Options: nosniff` and
195
+ never echo path/query/exception text into error bodies (CodeQL XSS / HTML).
196
+
197
+ ### Changed
198
+
199
+ - `/mcp` human-UX pass: status dashboard (AI on, active links, pending count,
200
+ expiry in hours), Pending/Decided proposal filters with tab badge, compact
201
+ decided cards, plain one-line diff summaries, stale dismiss + large-delete
202
+ typed confirm, Approve & deploy with deploy-type Advanced help, reject dialog,
203
+ access-link TTL presets (1h/4h/24h), Created/Last used link table, audit
204
+ labels without event codes, sticky tab nav, sign-in gate (no silent bounce),
205
+ and sidebar TTL hours + Review deep link to `/mcp#proposals`.
206
+
207
+ ### Added
208
+
209
+ - Targeted `replace_text` op for string fields (`template`, `func`, …): unique
210
+ `find` or 1-based `occurrence`; errors `400 text_not_found` /
211
+ `409 ambiguous_match` (with `matchCount`). Available via GET propose
212
+ (`node=&field=&find=&replace=`), patch JSON, and REST/MCP `submit_proposal`
213
+ (`payload.nodes` without a full tab). Multiple ops apply in order. AI guide
214
+ recommends it for small edits to long fields and documents a last-resort
215
+ placeholder→paste workflow when content exceeds draft limits.
216
+ - Layered reads on GET link, REST, and MCP (same auth/rate limits):
217
+ `GET …/flows/{id}?summary=1` (node id/type/name/wires + bytes, no field
218
+ bodies); `GET …/nodes/{id}` (one full node + flowId);
219
+ `GET …/nodes/{id}/field/{name}?lines=A-B` (optional line range +
220
+ `totalLines`/`bytes`); `GET …/search?q=&flow=` (hits with node/field/lines/
221
+ snippet; capped with `truncated:true`). Recommended loop: summary → search →
222
+ read line range → `replace_text` → propose. MCP tools: `get_flow` (`summary`),
223
+ `get_node`, `get_node_field`, `search_flows`.
224
+
225
+ ### Changed
226
+
227
+ - `/mcp/api` and `/mcp/a` use dual in-memory rate limits (per IP and per access
228
+ token) with configurable `aiAccess.rateLimitWindowMs` / `rateLimitMaxPerIp` /
229
+ `rateLimitMaxPerToken` (generous defaults: 600/min IP, 300/min token).
230
+ Exceeded limits return **429** `{ code: 'rate_limited', retryAfter }` and a
231
+ `Retry-After` header.
232
+ - Proposal `reviewUrl` is now an **absolute** URL from the request Host/protocol
233
+ (`X-Forwarded-*` only when Express `trust proxy` is set). Responses also
234
+ include relative `reviewPath` (`/mcp#proposal=<id>`).
235
+ - `displayName` datetime includes an explicit UTC offset and is documented as
236
+ **server local time** (for AI clients). The `/mcp` UI never shows that server
237
+ string: proposal headings and audit labels rebuild the title and format
238
+ `createdAt` / `at` with `Intl.DateTimeFormat` in the **browser** timezone.
239
+ `createdAt` remains ISO-8601.
240
+ - `/mcp` is served with `Cache-Control: no-store` so plugin upgrades do not keep
241
+ serving a cached admin client (inline CSS/JS).
242
+ - `/mcp` location hash reflects the active tab (`#status`, `#links`,
243
+ `#proposals`, `#audit`) via `history.replaceState`. `#proposal=<id>` is only
244
+ used while focusing a proposal deep link and is replaced with `#proposals`
245
+ after the scroll/highlight is consumed (so reload / returning to Proposals
246
+ does not re-trigger).
247
+
248
+ ### Fixed
249
+
250
+ - Side-by-side (split) diffs for large field replaces pair remove/add runs so
251
+ the AFTER column is visible instead of a long blank placeholder stack.
252
+ - Unknown flow ids return **404** `flow_not_found` (with hint to use ids from
253
+ `GET ./flows`) instead of **502** `upstream_error` on RedAdapter.
254
+ - Invalid draft chunk base64url (e.g. `@@@`) returns **400**
255
+ `invalid_chunk_data` and does not store the seq.
256
+ - `set.wires` is allowed in patch/propose when targets exist in the resulting
257
+ flow (validated); id/type/z stay protected.
258
+ - Added/removed node diffs include `wires` (readable) and `x`/`y`.
259
+ - `draft/new` checks live rev immediately (**409** `version_mismatch`); stale
260
+ submit responses set `draftDeleted: false` when the draft was kept.
261
+ - REST `Bearer bogus` / short tokens return `access_link_invalid` (with a
262
+ truncated-URL hint when applicable), not `access_link_missing`.
263
+ - Proposal diffs default to compact `format=summary` (changed lines + context +
264
+ byte sizes); `format=full` restores complete text.
265
+ - Re-submitting a draft returns **409** `draft_already_submitted` with
266
+ `proposalId`; malformed sha256 returns **400** `invalid_sha256`.
267
+ - Propose/draft responses warn with `siblingsOnSameRev` when other pending
268
+ proposals share the same flow revision.
269
+
270
+ ### Added
271
+
272
+ - Human-friendly proposals: optional `title` (≤80 chars) on all submit paths
273
+ (REST, MCP `submit_proposal`, GET `propose`, draft new/submit); responses
274
+ always include `title`, `displayName` (`title ·` server-local datetime), and
275
+ `reviewUrl` (`/mcp#proposal=<id>`). AI guides tell clients to cite
276
+ `displayName` + `reviewUrl` (not the raw id). `/mcp` list headings and audit
277
+ details use `displayName`; deep links open/scroll/highlight the proposal.
278
+
279
+ ### Changed
280
+
281
+ - Node added/removed diff blocks use a readable summary sentence, show key
282
+ fields (name, wires by node name, code/HTML), and hide the rest under “All
283
+ properties”. HTML templates offer a sandboxed iframe Preview toggle (`sandbox`
284
+ with no `allow-scripts`, `srcdoc`) plus the code view.
285
+ - `/mcp` Access Links: Copy link on each active row and on create (brief Copied
286
+ state + clipboard fallback); empty states; relative timestamps with absolute
287
+ on hover; confirm before revoke/approve/reject. List API includes `url` for
288
+ active in-memory links (raw `token` still create-only). Diff lines wrap in
289
+ unified and side-by-side views.
290
+
291
+ ### Fixed
292
+
293
+ - `/mcp` proposal diffs default to side-by-side on wide screens (unified below
294
+ the narrow breakpoint) and remember the toggle in `localStorage`; short
295
+ single-line fields in Node added/removed blocks stay inline (only long
296
+ multi-line text collapses).
297
+ - Proposal diffs compare against the **base flow snapshot** stored at submit
298
+ (`baseFlow`), so later approvals no longer make unrelated nodes look
299
+ “removed”. Pending+stale still warns and may include `vsCurrent`;
300
+ approved/rejected/failed never show the approve-would-fail banner.
301
+ - Added/removed nodes in the `/mcp` UI render as single “Node added” / “Node
302
+ removed” blocks (properties collapsed; long text expandable).
303
+ - Unknown paths under `/mcp/a/*` return JSON `{ code: not_found }` without
304
+ echoing the access-link token (no HTML `Cannot GET`).
305
+ - Draft `append` `totalBytes` counts **decoded** chunk bytes vs `maxBytes` (not
306
+ base64url character length).
307
+ - Field-mode `draft/new` validates that `node`/`field` exist on the live flow
308
+ before upload (`mode=json` may add/remove nodes and skips that check).
309
+ - Proposal diffs for added/removed nodes include all properties; long text
310
+ fields (`template`, `func`, …) are line-diffed as all-added / all-removed.
311
+ - Draft append “no gaps” hint no longer reads like the upload is finished; error
312
+ hints are code-specific (e.g. `chunk_conflict` vs stale rev).
313
+ - `/mcp` audit log actor cells expose the full label via `title` when truncated;
314
+ sidebar AI Access TTL/deploy labels stack above their inputs.
315
+ - `/mcp` page uses a wide responsive container (`max-width` ~1400px / 95vw);
316
+ proposal diffs default to side-by-side on wide screens with a unified toggle;
317
+ long code/diff blocks scroll horizontally with monospace line numbers.
318
+
319
+ ### Added
320
+
321
+ - GET patch / `mode=json` drafts support `nodes:[{op:'add'|'remove'|'set',...}]`
322
+ (plus full `replace_flow`); docs cover exact JSON shapes and ~4–5 KB raw chunk
323
+ guidance.
324
+ - Self-contained GET access links at `/mcp/a/<token>` for chat AIs that can only
325
+ HTTP GET (markdown docs; scoped status/flows/proposals/propose/drafts; chunked
326
+ drafts for large fields; `Cache-Control: no-store`; per-link rate limit; token
327
+ redaction in paths). Create-link responses include the full `url`; default
328
+ link TTL is **4 hours** (configurable).
329
+
330
+ ### Fixed
331
+
332
+ - Shared-read REST routes (`/flows`, `/proposals`, …) return
333
+ `access_link_missing` / `access_link_invalid` with Bearer `WWW-Authenticate`
334
+ (not passport `auth_required` / realm=`Users`) when an access-link token is
335
+ missing or invalid.
336
+ - `GET /flows/{id}` always includes `flow.type` (defaults to `tab`) so REST
337
+ matches OpenAPI `FlowTab` and MCP `get_flow`.
338
+ - Unknown paths under `/mcp/api/v1` return JSON `{ code: not_found }` instead of
339
+ HTML `Cannot GET`.
340
+
341
+ ### Added
342
+
343
+ - `GET /mcp/api/v1` unauthenticated discovery index (endpoints, auth scheme,
344
+ OpenAPI URL, MCP endpoint).
345
+ - `GET /status` accepts access-link Bearer and returns caller label, expiry,
346
+ permissions, and base URLs.
347
+ - OpenAPI “Quick start for access-link clients” with example
348
+ `CreateProposalRequest`; `/mcp` **Copy link for AI** includes API base + docs
349
+ hint with the token.
350
+
351
+ ### Removed
352
+
353
+ - Legacy standalone MCP server (Express/OAuth/SSE entrypoints, Docker images,
354
+ Playwright e2e against `/health`, and related dependencies). The Node-RED
355
+ plugin (`/mcp`, `/mcp/api/v1`, `/mcp/rpc`) is the supported surface.
356
+
357
+ ### Added
358
+
359
+ - Node-RED plugin scaffold (`ai-access.cjs` / `dist/plugin.cjs`) with `GET /mcp`
360
+ admin page and `GET /mcp/api/v1/status`.
361
+ - `aiAccess` settings hook (`allowWithoutAdminAuth` and reserved fields for
362
+ later link TTL, max links, and deployment type).
363
+ - Optional `node-red` peerDependency (`>=4.0.0`).
364
+ - MCP Streamable HTTP endpoint at `POST /mcp/rpc` (access-link Bearer tools
365
+ mirroring the AI-facing REST API).
366
+ - Flow runtime adapter (`RedAdapter` via `RED.runtime`, `HttpAdapter` Admin API
367
+ fallback, factory selection) with rev-checked `updateFlow` (default deployment
368
+ type `nodes`).
369
+ - In-memory access-link store and admin routes under `/mcp/api/v1/links`
370
+ (default TTL 24h, max 10 active, token shown once; Bearer middleware for AI
371
+ clients).
372
+ - On-disk proposal store and audit log under `<userDir>/.ai-access`, plus REST
373
+ routes for proposals, flows (with rev), and logs. Approve deploys via
374
+ FlowAdapter with rev checks; concurrent approve guarded.
375
+ - Trusted write helper for `.ai-access` (call-site file-write suppressions
376
+ removed; sole trust-boundary annotations live in the helper): directory mode
377
+ `0o700`, file mode `0o600`, and size caps on proposal JSON and audit appends
378
+ (`413` when exceeded).
379
+ - `/mcp` admin UI for access links (TTL, show-once token, revoke), proposals
380
+ (summary, approve with deploy type, reject, rev-conflict messages), audit log,
381
+ and status. Read-only for `read` users; mutating controls for `*` only.
382
+ Optional `deploymentType` on approve; status exposes link/deploy defaults.
383
+ - OpenAPI 3.1 spec for `/mcp/api/v1` (status, links, flows, proposals, logs,
384
+ auth, 413 limits) served at `GET /mcp/api/v1/openapi.yaml`; README install,
385
+ config, `/mcp` usage, and AI quickstart.
386
+
387
+ [0.1.1]: https://github.com/com55/node-red-ai-access/compare/v0.1.0...v0.1.1
388
+ [0.1.0]: https://github.com/com55/node-red-ai-access/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) ziv-daniel
4
+ Copyright (c) 2026 com55
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.