@meada/meada 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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,599 @@ All notable changes to Meada are recorded here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.2.0] - 2026-11-04
10
+
11
+ A minor release on the [1.x stability promise](https://github.com/ClaudioMascaro/meada/blob/main/docs/site/en/stability.md):
12
+ package reading (PEP 440 specifiers, uv sources, Go `replace` by a held module, `fetch` URLs a
13
+ function builds), resolution in the Rust, TypeScript and Gradle packs, the console's versions
14
+ page for a named workspace, the proposal server in the Compose and Helm recipes, SCRAM channel
15
+ binding to Postgres, CLI messages in Spanish, a generated first password for the console's
16
+ default `admin` account instead of a published one (#579), a refresh that keeps the language
17
+ groups no changed file touches (#391), Backstage and HTTP contract reading (tier d1, #613 to #621), and the fixes of tiers b6 to c5. The stored
18
+ manifest summary changes, so existing indexes are rebuilt once on first use. `meada-core` 1.2.0 deprecates `msg::pt()` in
19
+ favour of `msg::lang()` (`msg::lang() == msg::Lang::Pt`), types `effective::Diagnostic::code` as
20
+ `DiagnosticCode` (the JSON is unchanged) and makes `named::message_problem("")` return `Some`;
21
+ the new `msg::Lang` and `effective::DiagnosticCode` are `#[non_exhaustive]`, so a match on
22
+ either needs a wildcard arm. A crate that declares `meada-core = "1.1"` meets the last two
23
+ changes on `cargo update`, and `=1.1.0` stays on the old API. The tree, the `meada-core` pin, the
24
+ Dockerfile, the compose defaults and the Helm chart declare `1.2.0`, and the `v1.2.0` tag goes
25
+ on the `release/1.2` branch, cut from this entry's merge on main. Publication
26
+ (crates, the staged npm package, the GitHub draft release) belongs to the maintainer.
27
+ Release notes are available in
28
+ [pt-BR](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.2.0.md),
29
+ [English](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.2.0.en.md) and
30
+ [Spanish](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.2.0.es.md).
31
+
32
+ ### Added
33
+
34
+ - Backstage backends: the router a backend plugin gives its `httpRouter`
35
+ (`coreServices.httpRouter`) is served under `/api/<pluginId>` when `createBackendPlugin` writes
36
+ its `pluginId` as a literal or as a `const` of the file bound to one, so two plugins with the
37
+ same relative path no longer collide, and a URL
38
+ that starts with `discovery.getBaseUrl('<id>')` (held by a constant or written in place) starts
39
+ at `/api/<id>`, its link's reason naming the plugin's mount (as does a hostless call of a route
40
+ the plugin serves in its own repository). A plugin whose `pluginId` cannot be read stays at the
41
+ root, and `meada status` names it. TypeScript and JavaScript functions now give their `return`
42
+ values and an arrow's expression body to the value flow, so a router a factory returns
43
+ (`httpRouter.use(await createRouter())`) is followed (#615).
44
+ - Backstage proxy: a TypeScript or JavaScript `fetch` whose URL starts with `/api/proxy/<endpoint>`
45
+ (also `discovery.getBaseUrl('proxy')` plus `/<endpoint>`) is a call to the `target` of that
46
+ endpoint in `proxy.endpoints` of an `app-config*.yaml`: a `${VAR}` target links through the
47
+ peer's `base_url_env` and a literal `http(s)://` target by host, the link's reason naming the
48
+ endpoint, and any other target leaves the call unlinked, which `meada status` says. A
49
+ `pathRewrite` that only strips the endpoint is followed; any other one, `ignorePath`,
50
+ `prependPath: false` and an endpoint the `app-config*.yaml` files disagree on leave the call
51
+ unlinked too (#616).
52
+ - Go: a struct field tagged `env:"X"` (cleanenv, caarlos0/env) or `envconfig:"X"`
53
+ (kelseyhightower/envconfig) is the environment read `X` where the field is read
54
+ (`cfg.API.URL`), so `base_url_env` links such a call as `inferred` instead of `ambiguous`
55
+ (#618).
56
+
57
+ - A Python pydantic-settings field is an environment read: a field `f` of a `BaseSettings`
58
+ subclass of the same file is the variable `<env_prefix><F>` (upper case), or its `alias` /
59
+ `validation_alias`, so the peer's `base_url_env` links `f"{settings.f}/orders"` as an
60
+ environment read does instead of leaving it `ambiguous`; other classes are unchanged (#619).
61
+ - A TypeScript or JavaScript base URL read through Backstage's `config.getString('a.b')` or
62
+ `getOptionalString('a.b')` is the variable `VAR` when an `app-config*.yaml` of the repository
63
+ holds `a.b: ${VAR}`, so the peer's `base_url_env` links the call as an environment read does
64
+ instead of leaving it `ambiguous`; a literal value or a key no file holds leaves the base
65
+ unresolved (#617).
66
+ - A PyPI version specifier is checked against the provider's version as PEP 440 says, as npm's
67
+ range is: `range mismatch` when the specifiers (`==`, `!=`, `<`, `<=`, `>`, `>=`, `~=`, `==X.*`
68
+ and `===`, joined by commas) reject the local version, nothing added when they accept it, and
69
+ `range unchecked` kept for a provider without a version and for a specifier it cannot read (a
70
+ Poetry `^1.2`, an unknown operator). A pre-release version is rejected unless a specifier
71
+ names one, and a mismatch removes no candidate (#534).
72
+ - A TypeScript or JavaScript `fetch` whose URL a function of the repository builds is a consumer:
73
+ a call to a function whose body is one returned string (an arrow function's expression body, or
74
+ a lone `return`) folds to it with the call's arguments, at the `fetch` and through a constant,
75
+ across imports. A part that does not fold, such as a base read from `process.env`, leaves the
76
+ consumer unresolved (#536).
77
+ - A Go `replace` by another module (`replace a => github.com/owner/repo`) keeps, among the providers
78
+ of the required module, the one in the workspace repository that path names, `exact`, for the
79
+ `require` and for the calls through its imports, instead of dropping the dependency; a
80
+ replacement no repository holds stays out (#532).
81
+ - A PyPI dependency with a uv source in `[tool.uv.sources]` links to the one package it names,
82
+ `exact`, for the entry and for the calls through its imports: `workspace = true` the member of
83
+ the consumer's uv workspace (`[tool.uv.workspace] members` less `exclude`), `path` the package
84
+ at that path, `git` the workspace repository of its URL; a `url` or `index` source stays out.
85
+ An entry without a uv source keeps linking to every package of its name (#533).
86
+ - The CLI messages (`--help`, `status`, `meada.toml` and index errors, and every other message of
87
+ the catalogs) are also in Spanish, selected when `LANG` starts with `es`; other values keep
88
+ falling back to English, and the MCP output stays English (#103).
89
+ - The workspaces profiles run the proposal server: `compose.proposals.yaml` and
90
+ `proposals.workspace.toml` in Compose (its own pull and volume, the read role, TLS on
91
+ `127.0.0.1:8445`) and an opt-in `proposals` block in the Helm chart (Deployment, Service,
92
+ bootstrap and probes with `timeoutSeconds`, absent by default); `scripts/compose-check` and
93
+ `scripts/helm-check` assert both. The identity provider recipes say how a person or an agent
94
+ gets a token whose `aud` is `[proposals] audience` (Entra ID, Okta, Keycloak, local accounts; Okta
95
+ needs a second authorization server the chart cannot render), in pt-BR, English and Spanish (#504).
96
+ - Over TLS, the Postgres client of the data layer authenticates with SCRAM channel binding
97
+ (`tls-server-end-point`, RFC 5929): it runs `SCRAM-SHA-256-PLUS` whenever the server offers
98
+ it, so a client that requires channel binding connects (#483). Loopback without TLS keeps plain
99
+ `SCRAM-SHA-256`.
100
+ - The console's named workspace view gains a versions page (#503): the versions newest first,
101
+ paged with the server's cursor; one version's entries, manifest text and diff against the
102
+ current one as the route answers; the history for operators and the administrator (a viewer
103
+ has no history control); and applying a listed version, which is a rollback when it was
104
+ current before, through the editor's confirmation at the base the page read. A stale base and
105
+ a refused entry show the server's message and the page reads the versions again. In pt-BR and
106
+ English.
107
+ - Gradle coordinate holes from `gradle.properties` and version catalogs (#467): a dependency
108
+ written `implementation(libs.models)` or with a `${name}` or `$name` the script leaves open
109
+ now links to the package providing its coordinate. `gradle.properties` of the repository root,
110
+ the settings file's directory and the module (the module's wins, and a name the script assigns
111
+ is never filled) feeds the same hole filler as the script's own declarations, and
112
+ `gradle/libs.versions.toml`, or a `*.versions.toml` a settings `from(files("..."))` names by a
113
+ relative path, maps `libs.<alias>` (dashes and underscores as dots) to `group:artifact` and
114
+ its version through `[libraries]` and `[versions]`; an alias the catalog lacks declares
115
+ nothing. Both files are bounded (`lang::MAX_BYTES`, 8192 entries) and have rows in the
116
+ manifest probes. `buildSrc`, convention plugins, included builds and build-time BOMs stay
117
+ unread. The stored manifest summary gains Gradle's `template` and catalog placeholders, so
118
+ existing indexes rebuild once (ADR 0004); the `conformance-java` export gained two links.
119
+ - Rust item macros in associated-item position and by `crate::` (#505, after #398): an
120
+ invocation of a qualifying item macro among the items of an `impl` or a trait gives its
121
+ body's methods, associated consts and types to that block, under the same rules (first arm
122
+ only, the attributes on the invocation, the same `cfg` handling), and `crate::m! { .. }`
123
+ qualifies as `m!` does; `other::m!`, `self::m!` and `super::m!` stay unread. `meada decide
124
+ --decider` now parses a file under the setting the index stored for it, so a function from an
125
+ item macro body is function-like and its span is sent.
126
+ - TypeScript and JavaScript: a `tsconfig.json` (or `jsconfig.json`) with `extends` naming a
127
+ relative path inside the repository takes the `paths` and `baseUrl` of the chain, the nearest
128
+ config that declares each option winning (#465), so the alias imports under a monorepo's
129
+ `packages/*` whose configs only extend the root's resolve. A package, a path outside the
130
+ repository, a chain of more than 8 configs after the nearest and a cycle are not followed (the
131
+ nearest config alone serves). Project `references` and a base not named `tsconfig.json` or
132
+ `jsconfig.json` are still not read.
133
+
134
+ ### Fixed
135
+
136
+ - Go: a method named like a resty verb (`Get`, `Post`, `Put`, `Patch`, `Delete`, `Head`,
137
+ `Options`) called on a struct field that holds a repository, a Kubernetes client or a cache
138
+ client (`s.repo.Get(ctx, id)`) is no longer an HTTP consumer with an unresolved URL, so
139
+ `meada decide` lists no open item for it; a field holding a resty request or client keeps its
140
+ consumers (#621).
141
+ - A route whose handler sits in a test file (`*_test.go`, `*.test.*`, `*.spec.*`, `test_*.py`,
142
+ `*_test.py`, a `tests` or `__tests__` directory, `src/test`) is no provider: a test's router
143
+ or fake upstream no longer shows in `search` and the export, and no longer makes the client
144
+ repository a candidate for the route it consumes, so those calls link to the only real server
145
+ instead of turning `ambiguous`. The test code stays indexed; `test_routes = true` in
146
+ `meada.toml` keeps the routes as providers (#620).
147
+ - A comment inside a Go parameter list or argument list (`func NewRouter( //nolint:funlen`,
148
+ `NewRouter( // engine`) is no longer read as a parameter or an argument: it took position 0, so
149
+ a router handed to such a function reached none of its routes. The shared child walk of the
150
+ packs now skips comments, which also fixes the same shift in the TypeScript pack (#613).
151
+
152
+ - Express routes registered on an `express-promise-router` router (the Backstage backend default)
153
+ are provided: its default import counts as a router factory under any local name (#614).
154
+ - A refresh resolves a Swift file as a cold index does: the type parameters of a type or
155
+ function (`Page<Item>`) are kept in the index, so an `Item()` in an extension of `Page` in
156
+ another file is no construction of a type named `Item` after an edit to an unrelated Swift file
157
+ (the stored format changes, so an existing index is rebuilt once) (#609).
158
+ - A Kotlin `private` constructor, primary (`class C private constructor(..)`) or secondary, is
159
+ called only from inside its class: a call from another class no longer resolves to it, one from
160
+ the class, its companion or a nested class stays `exact`. `internal` is still not enforced
161
+ (#455).
162
+ - A Rust name two globs give (`use x::*; use y::*;`, which compiles only under `cfg`
163
+ alternatives) is `ambiguous` between them, not `exact` to the latest glob; an explicit item or
164
+ `use` beside the globs still wins (#439).
165
+ - A Swift parameter written as a name from outside the repository (`Ext.CompletionHandler`, which
166
+ may be an alias of a function type) neither takes nor refuses a trailing closure with certainty:
167
+ a call that fits an overload only through it is `ambiguous` among its overloads (`inferred` when
168
+ it is the only one), no longer `exact` to a sibling overload that reads as a function type or
169
+ absent. A parameter written as a type the repository declares or a standard value type still
170
+ refuses it (#456).
171
+ - TypeScript and JavaScript: `exports.y = function () {}` and `module.exports.y = ..` define the
172
+ symbol `exports.y` (exported as `y`), so a bare `y()` in the file no longer links to it and
173
+ `m.y()` through an import still does (#457).
174
+ - A PyPI package in the consumer's own repository that no uv source names links `inferred`, not
175
+ `exact`, when it is the one package of the name, with the reason "no uv source names the local
176
+ package, the registry package is the likely provider": pip and uv install the registry's
177
+ package, so a same-named stub (uv's `anyio_local`) is only a candidate. A source naming it
178
+ (`workspace = true`, `path`) and a single provider in another repository stay `exact` (#535).
179
+ - The `golden_diff` example exits with a message naming the range's refs and the `--range A...B`
180
+ flag when a merge-base cannot be found (a shallow or single-branch clone has no `origin/main`),
181
+ and with a usage error for `--range` without a value, instead of panicking (#592).
182
+ - `[postgres] schema` starting with `pg_` (reserved by Postgres) is refused at manifest read with
183
+ Meada's own message, in pt-BR and English, instead of Postgres's raw error at `meada postgres
184
+ migrate` (#482).
185
+ - The Helm node readiness probe sets `timeoutSeconds` (`readiness.timeoutSeconds`, default 8), so a
186
+ Postgres or Valkey that drops packets no longer exceeds the kubelet's 1 s default and marks every
187
+ node unready (#448).
188
+ - The container build copies every top-level `tests/fixtures/*.json` in the UI stage with one
189
+ `COPY`, so a UI test importing a new fixture no longer breaks the image (#495).
190
+ - The deploy fetch scripts (Compose `fetch-pulled.sh` and the chart `workspace.fetch`) read a
191
+ repositories manifest whose `repo` and `path` keys are written as quoted keys (`"repo" = ...`);
192
+ the shared awk program skipped them. Its test now takes the expected pairs of every case from the
193
+ `toml` crate instead of hand-written lists (#568).
194
+ - Rust: a `crate::a::*` glob written inside `a` or below it sees what `use super::*` sees,
195
+ the ancestor's private `use` included, so `Def::new()` through it is `exact` instead of
196
+ unresolved (#438). A glob of a sibling module still takes public names only.
197
+
198
+ ### Changed
199
+
200
+ - An Express app or router a TypeScript or JavaScript function returns now takes the prefixes of
201
+ the mounts it is given to: `app.use('/v1', makeRouter())` serves `makeRouter`'s routes under
202
+ `/v1/...`, where they were served at the root, and the links of consumers of those paths change
203
+ with them (#615).
204
+ - A refresh keeps the rows of each group of language packs that resolve together (TypeScript and
205
+ JavaScript, Rust, Python, ...) when no file of the group changed and the config files,
206
+ manifests, file list and exports did not move: its contracts are not extracted again, its calls
207
+ are not resolved again and its files are not parsed again for their values. A one-line edit of
208
+ a Rust file of this repository refreshes in 3.3 s where it took 3.9 s (release build, median of
209
+ five); the export stays byte-identical to a cold one. A change of Meada's version re-extracts
210
+ every group once (#391).
211
+ - The console no longer creates the default account `admin` with a published password: without
212
+ `admin_password_env` or `admin_password_file`, the start that creates it generates the first
213
+ password, stores it with a change required, and prints it once on stderr (`accounts: default
214
+ account admin created; first password: ...`, right after the listening line; `docker compose
215
+ logs console` in the Compose recipe). No later start prints it; a lost one is recovered with
216
+ `meada ui reset-admin`. The password policy's `default_password` rule goes with the published
217
+ password, and ADR 0024 is amended (#579).
218
+ - The console asks `meada-core` through WebAssembly (`namedNameProblem`, `namedDescriptionProblem`,
219
+ `namedMessageProblem`, `resourceRoles`) whether a workspace name, description and version
220
+ message are valid and which resource roles exist, instead of keeping its own copy of the rule,
221
+ its bounds and the role list (#501). A version message is refused when empty by the same
222
+ function on the browser, the console API and `meada workspaces`: the empty-message refusal now
223
+ reads "a message is 1 to 500 characters, ..." instead of the request-body shape, and the
224
+ refusal of a too-long or control-bearing message reads "1 to 500" where it read "at most 500".
225
+
226
+ ## [1.1.0] - 2026-11-02
227
+
228
+ A minor release on the [1.x stability promise](https://github.com/ClaudioMascaro/meada/blob/main/docs/site/en/stability.md):
229
+ local accounts (ADR 0024) in the console, the proposal server and the nodes, carried by the
230
+ `cloud` image, the Compose recipe and the Helm chart; the export's `format` and indexed commit;
231
+ client-side deadlines on every Postgres call; durable pulled-generation writes; resolver fixes
232
+ for C#, Kotlin, Rust and Swift (tier b3); and the fixes of tiers b1 and b2. The index schema
233
+ version changes, so existing indexes are rebuilt once on first use. `meada-core` 1.1.0 adds `format`, `commit` and `dirty` to `Export`, and its
234
+ `export::parse` refuses a document without `format`: re-export with 1.1.0 before parsing an export
235
+ written by 1.0.0. The tree, the `meada-core` pin, the Dockerfile, the compose defaults and the
236
+ Helm chart declare `1.1.0`, and the `v1.1.0` tag follows this entry's merge on main. Publication
237
+ (crates, the staged npm package, the GitHub draft release) belongs to the maintainer.
238
+ Release notes are available in
239
+ [pt-BR](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.1.0.md),
240
+ [English](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.1.0.en.md) and
241
+ [Spanish](https://github.com/ClaudioMascaro/meada/blob/main/docs/releases/1.1.0.es.md).
242
+
243
+ ### Added
244
+
245
+ - The export format and the indexed commit (#512, ADR 0004 "Canonical export"): every export
246
+ starts with `format` (`meada_core::export::FORMAT`, 1), which rises only when a reader of the
247
+ previous shape would misread the new one, never for an added optional field; then
248
+ `repository`, then `commit` and `dirty`, both optional and left out together. Locally `meada export` reads `HEAD` before and
249
+ after its refresh and the checkout's status after it (ignored files, `.meada/` among them, do
250
+ not count), and names the commit only when `HEAD` did not move and the index is fresh; outside
251
+ git or before the first commit both are left out. In server mode they come from the commit
252
+ `meada index --workspace` recorded beside the index, or a generation's `head`, never from the
253
+ mirror's live `HEAD`, with `dirty` false. For `meada-core` crate users: `Export` gains
254
+ `format`, `commit` and `dirty` (a minor change, the struct being `#[non_exhaustive]`, so the
255
+ next `meada-core` release is 1.1.0), and `export::parse` refuses a document without `format`,
256
+ naming the field, so an export written before this release no longer parses. Every `*.export.json` golden gained the three fields.
257
+
258
+ - Named workspaces and the proposal server with local accounts (#562, ADR 0024, from #551):
259
+ `[catalog]` and `[workspaces]` (and so `[proposals]`) accept `[accounts.github]` in place of
260
+ `[oidc.github]` and still need one of the two (`[catalog] needs [oidc.github] or
261
+ [accounts.github]`; `[workspaces]` now names `[ui]` and `[catalog]`, the catalog naming the
262
+ provider). Eligibility reads the account's verified login, an operator account is the platform
263
+ administrator, and workspace operator lists, version authors, history and audit records name
264
+ `local:` subjects. `POST /api/v1/account/tokens` takes `{"surface": "proposals"}` when the
265
+ console's bootstrap has `[proposals]` (audience `meada:proposals`; a 422 `invalid_surface`
266
+ without it), `config` carries `"proposals": true` and the profile page offers the surface. The
267
+ proposal server with `[accounts]` and no `[oidc]` reads the public key at start and admits only
268
+ those tokens (a session token or a node's agent token is a 401 with `WWW-Authenticate: Bearer`,
269
+ no protected resource metadata), deriving the subject, login, groups, grant and role from the
270
+ token alone. No golden changed.
271
+ - The verified GitHub login of local accounts (#561, ADR 0024, from #551): `[accounts.github]`
272
+ (`host`, `roles`, `max_age_seconds` as `[oidc.github]`, plus `api`, `https://api.github.com` by
273
+ default on `github.com` and required on any other host) is the GitHub grant provider of local
274
+ accounts. A person pastes a GitHub personal access token on their profile page or sends it to
275
+ `POST /api/v1/account/github`; the console calls `GET /user` on `api` once, keeps the lowercase
276
+ login and drops the token, and answers a fresh session token carrying the login. A login
277
+ another account holds is a 409 `login_taken`, GitHub's refusal a 422, GitHub out of reach a
278
+ 503. `POST /api/v1/account/github/remove` and the accounts page's `remove_github` action remove
279
+ it. Session and agent tokens carry the verified login, so the GitHub grant joins the groups
280
+ grant in the console (`session` shows `login`, `github_host` and `github_grant`), on nodes, in
281
+ a team operator's additions (`added_by`), in the audit's `login` column and in the exclusions
282
+ marks; `meada github-app roles` reads `[accounts.github]`. Recorded `account.github` and
283
+ `account.remove_github`; the personal access token is never stored, logged or audited. No
284
+ golden changed.
285
+
286
+ - Helm chart support for local accounts (#565, ADR 0024, from #551): `modules.accounts` renders
287
+ `[accounts]` from values, with `values-accounts.yaml` as the proof-of-concept shape (a writable
288
+ console with `operations = true`, Postgres and no identity provider). The Ed25519 private key
289
+ comes from its own Secret and is mounted only in the console's `console` container, the public
290
+ key from another Secret in the console and the nodes (a node also gets `[ui] public_url`, the
291
+ token issuer, and `[postgres]`), the initial admin password from an optional Secret in the
292
+ console. `modules.accounts.groups` and `modules.accounts.github` carry `[accounts.groups]` and
293
+ `[accounts.github]` (the refresh job, with `modules.githubApp`, gets the GitHub grant provider and runs the role check, and
294
+ `modules.workspaces` accepts it in place of `modules.oidc.github`); `modules.accounts.breakGlass`
295
+ keeps `[accounts]` in the console alone beside `modules.oidc`. The chart refuses a missing
296
+ Postgres or console, equal key Secrets, accounts beside OIDC without break glass, and groups or
297
+ GitHub under break glass. `scripts/helm-check` covers the sections, the mounts and the refusals;
298
+ the chart READMEs (pt-BR, English, Spanish) no longer say a writable console needs OIDC. The
299
+ proposal server is not part of the chart. `[accounts.github]` renders as the spec names it and
300
+ is parsed once #561 lands. No golden changed.
301
+
302
+ - One-command proof of concept in the Compose recipe (#564, ADR 0024, from #551):
303
+ `cp .env.accounts.example .env && docker compose up -d` starts the generations fleet, Valkey,
304
+ the store, Postgres with its migration, a writable console with local accounts and nodes that
305
+ admit agent tokens. `compose.accounts.yaml` adds the Ed25519 key pair (made once by the
306
+ `certificates` step, never printed, the private key mounted read-only in the console alone and
307
+ the public one in the nodes), the console's and the nodes' `[accounts]` manifests, a one-shot
308
+ `seed` of the first workspace version (only while the store has none) and a node proxy that
309
+ forwards `Authorization` with no static bearer. The other profiles are unchanged, and
310
+ `scripts/compose-check` covers the new one. The Compose README (pt, en, es) starts with it and
311
+ covers `MEADA_ADMIN_PASSWORD`, `meada ui reset-admin`, key rotation and rate limiting the
312
+ sign-in route at the proxy.
313
+
314
+ - Agent tokens for the nodes (#560, ADR 0024, from #551): a signed-in local account generates,
315
+ on its profile page or through `POST /api/v1/account/tokens` (`{surface: "nodes", hours}`, 1 to
316
+ 168 hours, 8 by default), an agent token shown once (`{token, expires_at, surface}`), signed
317
+ with the account's role and groups as its row stands and a random token id, recorded
318
+ `account.token` (surface, hours, token id, never the token). A change-required account gets the
319
+ 403 `password_change_required`, a suspended one the role refusal; the console answers an agent
320
+ token with 401. A node with `[accounts]` and no `[oidc]` (`meada mcp --listen`) now reads the
321
+ signing public key at start, and the console's `[ui] public_url` from a `[ui]` section its
322
+ manifest must carry, refusing to start without either; it admits only agent tokens for the
323
+ nodes (a 401 `Bearer` before routing for any other, a session token included) and answers
324
+ under the grant `[accounts.groups]` gives their groups (every repository without the table),
325
+ as an identity provider's token is answered. The `accounts` feature now implies `ui`. No golden
326
+ changed.
327
+
328
+ - Accounts page in the console (#559, ADR 0024, from #551): the global operator of a console with
329
+ local accounts gets `/accounts`, listing every account (role, groups, state with a suspended
330
+ account marked and a locked one saying until when, change required, last password change), a
331
+ create form (username pattern and password length checked first, "change on first sign-in"
332
+ checked by default) and, per account, role, groups, suspend, reactivate and reset password,
333
+ each behind the shared confirmation dialog with the server's refusals (`last_operator` and the
334
+ rest) shown unchanged. Any other role, and a console under break glass, gets the not-found
335
+ page at that path. The audit page names every `account.*` action in Portuguese and English.
336
+ The password rule `common_password` now has its own copy. Front end only, no golden changed.
337
+
338
+ - Groups of local accounts (#558, ADR 0024, from #551): the global operator gives accounts groups
339
+ (`groups` on `POST /api/v1/accounts`, and the `groups` action of
340
+ `POST /api/v1/accounts/<username>`, each an owner name, else a 422 `invalid_group`);
341
+ `GET /api/v1/accounts` lists them, and each change is recorded `account.groups`.
342
+ `[accounts.groups]` maps groups to identities as `[oidc.groups]` does: once it exists, a local
343
+ session's grant is what its groups map to, and it bounds every view (the manifest, the
344
+ workspace and its versions, the store, the repositories, the credentials, the playground, the
345
+ exports and the graph views) as an identity provider's grant does; without it every local
346
+ account still reads every repository. A local viewer whose group owns an entry of the current
347
+ workspace version its grant reads is a team operator (ADR 0015). Session tokens carry the
348
+ groups, so a change reaches reads at the next sign-in and writes at once (the account row is
349
+ read before each). `GET /api/v1/admission` with `[accounts]` now answers: `accounts` (the mode,
350
+ `accounts` or `break_glass`, and the signing public key's fingerprint, `blake3:` and the hex
351
+ BLAKE3 hash of the raw Ed25519 key) and, without `[oidc]`, the groups table bounded by the
352
+ caller's grant. No golden changed.
353
+
354
+ - Account administration for local accounts (#557, ADR 0024, from #551): the global operator
355
+ lists every account (`GET /api/v1/accounts`: username, role, state, the end of a lock, change
356
+ required, last password change, created and created by, never a hash), creates one
357
+ (`POST /api/v1/accounts`, `{username, role, password, change_required}`, the policy applied to
358
+ the temporary password, a change required unless the body turns it off; a malformed username a
359
+ 422 `invalid_username`, a taken one a 409 `username_taken`) and changes one
360
+ (`POST /api/v1/accounts/<username>`, one `action`: `role`, `suspend`, `reactivate` or
361
+ `reset_password`, which clears a lock and requires a change unless told not to; an unknown
362
+ account a 404). Suspending or demoting the last active operator is a 409 `last_operator`,
363
+ decided under the schema's advisory lock so two requests at once never leave none. Anyone else
364
+ gets a 403. The routes answer whatever `[ui] operations` says; workspace and generation writes
365
+ keep requiring it. Every console write of a local account now reads the account's row first,
366
+ so a suspended or demoted account loses its writes at once, while its reads last until its
367
+ token expires. Audit actions `account.create`, `account.role`, `account.suspend`,
368
+ `account.reactivate` and `account.reset_password` name the account and the fields changed,
369
+ never a password, written before the change (503 `audit_unavailable` otherwise); `account` is
370
+ the route-level action of a change refused before its body is read. No route deletes or
371
+ renames an account; under `[accounts] break_glass` (#563) none of these routes exists, each a
372
+ 404. No golden changed.
373
+
374
+ - Break-glass account beside the identity provider (#563, ADR 0024, from #551): `[accounts]
375
+ break_glass = true` lets the section sit beside `[oidc]`; without `[oidc]` it is an error, and
376
+ `[accounts.groups]` or `[accounts.github]` under it is an error naming the table. The console
377
+ then signs in only the default account (any other username gets the wrong password's 401,
378
+ audited `not_break_glass`, the table never read) as the global operator, and admits its session
379
+ token beside the identity provider's, each bearer routed by its issuer to one verifier, so the
380
+ identity provider's keys never check a console token and the signing key never checks an
381
+ identity provider's; a console whose `[oidc] issuer` is its own `public_url` refuses to start.
382
+ The password change works; no other route of local accounts exists. Nodes and the proposal
383
+ server keep admitting only the identity provider and read no key. `config` adds `break_glass:
384
+ true`, and the front end offers a discreet break-glass sign-in (`/break-glass`) beside the
385
+ identity provider's, which now waits for a click under break glass. No golden changed.
386
+
387
+ - Hardening of local sign-in (#555, ADR 0024, from #551): the password policy refuses an embedded
388
+ common-password list (SecLists, MIT, the entries of 12 to 128 characters, compared ignoring
389
+ case; rule `common_password`). Ten consecutive failed password checks, at sign-in or as a
390
+ password change's current password, lock an account for fifteen minutes, counted in a
391
+ transaction holding the account row so parallel attempts never pass ten; a success resets the
392
+ count. A locked account gets the wrong password's 401 at a hash's cost, its password unchecked
393
+ and its lock never extended, audited `locked_now` and then `locked`. A stored hash weaker than
394
+ the console's parameters is redone at the next successful sign-in. `meada ui reset-admin
395
+ --workspace <manifest>` (features `ui` and `accounts`) creates or reactivates `admin` as an
396
+ operator, clears its lock and sets the `MEADA_ADMIN_PASSWORD` value or a generated password
397
+ printed once on stdout, with a change required, recorded `account.reset_admin` `via` `cli`
398
+ before the write and refusing with exit 1 when the record cannot be written. No golden changed.
399
+
400
+ - Local sign-in for the console (#554, ADR 0024, from #551): the new `accounts` cargo feature
401
+ (enabled by `cloud`) and its `[accounts]` section, which needs `[postgres]` and never sits
402
+ beside `[oidc]`, name the Ed25519 signing key pair and the default account's initial password,
403
+ each from a variable or a file. Migration 9 adds the `accounts` table, so `meada postgres
404
+ migrate` reaches version 9. On its start the console checks the key pair and creates the
405
+ default account `admin` (password `admin123` with a change required, or the policy-checked
406
+ `MEADA_ADMIN_PASSWORD` without) once, under an advisory lock. `POST /api/v1/login` answers a
407
+ session token the console signs with EdDSA for eight hours; a token carrying the change-required
408
+ mark opens only `POST /api/v1/account/password`. Every route but the static files, `config` and
409
+ `login` then needs a session token; `[ui] operations = true` is accepted with `[accounts]` and
410
+ no `[oidc]`; `config` names the sign-in mode (`sign_in`: `accounts`, or `oidc` with an identity
411
+ provider), `session` adds `account: true`, and
412
+ every account reads every repository while no groups table bounds it. Passwords are argon2id at
413
+ OWASP's parameters under a policy of 12 to 128 characters that refuses the default password and
414
+ the username, at most four hashes run at once, and every sign-in, refusal and password change
415
+ is audited (`account.login`, `account.password`, role `none` for an unknown username) before its
416
+ token. The module table gains `accounts`; no golden changed.
417
+
418
+ - The console's sign-in pages for local accounts (#556, from #551): when `config` says
419
+ `"sign_in": "accounts"` the console shows its own sign-in page (labelled username and password,
420
+ one generic refusal, `busy` and `audit_unavailable` shown as themselves) instead of the identity
421
+ provider's redirect. A change-required sign-in goes straight to a forced password change page
422
+ (the current password and the new one twice, the server's rule shown on a refusal) that offers
423
+ nothing to navigate to until it succeeds, and then opens the workspace. The session token lives
424
+ in `sessionStorage` for the tab's life, is sent as the bearer and is cleared on sign-out and on
425
+ any 401 (which returns to sign-in; a refused current password in the change is not one); it is never in `localStorage`, a URL
426
+ or a log. A profile page offers the voluntary password change and sign-out. pt-BR and English
427
+ copy; the identity provider flow is unchanged. Front end only: no golden changed.
428
+
429
+ - `meada status` names a Kotlin file the grammar misreads (#546, from #434). A declaration read
430
+ as an infix call leaves the file out of the index; the file now sets the new `Facts::misparsed`
431
+ (absent from every other file's stored facts) instead of `unbuilt`, and a new status line,
432
+ `Msg::FileMisparsed`, in English and Portuguese, names it beside the byte-budget and using
433
+ drops. The Java and Kotlin layout skips it as it skips the other drops. The schema version is
434
+ the same: a file dropped before the upgrade gets its line when it next changes, or at once
435
+ after deleting `.meada/index.db`. The `cli.status-budget` goldens gained the new line.
436
+
437
+ ### Changed
438
+
439
+ - The grant providers take neutral inputs (#553, from #551): the new `grant` module computes a
440
+ subject's grant from its groups and its GitHub login (`Providers::grant`), with no reference
441
+ to a token, and holds the GitHub grant provider's permissions cache, which moved out of the
442
+ OIDC module; the OIDC module feeds it from a token's claims. Every reader of `[oidc.github]`
443
+ goes through `Manifest::github`, the console and the proposal server build their sessions
444
+ from a neutral admitted subject (`grant::Admitted`), and a node's pass carries only a grant.
445
+ Nothing a caller sees changes; no golden changed.
446
+
447
+ - The axum provider reader walks each value once per file (#431): the values a file's rebound
448
+ `let`s reach share one `seen` set, and `Code::origins` is not asked for a call whose builder
449
+ chain goes through a method no router hands back, nor for a name written as text, a path, a
450
+ number, a boolean or a character. The reader's share of a one-file refresh on this repository
451
+ drops from about 1.4 s to about 0.1 s. No golden changed.
452
+
453
+ ### Fixed
454
+
455
+ - Swift: a call whose labels differ from a known outside member's resolves as if that base
456
+ were absent (#463): `x.hash(seed: 1)` on a type that conforms to `Hashable` and declares
457
+ `hash(seed:)` is `exact`, while `x.hash(into: &h)` stays opaque. A call with no labels, or in
458
+ another language, is still compared by its bare name.
459
+ - Swift: an alias of an outside type reaches the repository's extensions of that type (#440). A
460
+ receiver typed by `typealias Anim = Animation`, or by an alias of an alias, and `Anim.build()`
461
+ match `extension Animation { }` as `Animation` does; an alias of an outside type with no
462
+ extension stays unresolved.
463
+ - Rust: a call after `?` or `.await` is typed by the value they unwrap (#435, after #401): the
464
+ pack keeps beside a function's written result the first type argument of a `Result` or
465
+ `Option` (`Def::unwrapped`) and the `Output = T` of `impl Future<Output = T>` and
466
+ `Pin<Box<dyn Future<Output = T>>>` (`Def::output`, read only through `.await`), so
467
+ `load()?.port()` and `fut().await.port()` resolve within `T`'s family, `exact` when it
468
+ declares one `port`, where `?` left a name match and a plain `fn` returning a future resolved
469
+ to nothing. A type outside the repository, or a `?` before an `.await`, leaves the call as
470
+ it was. The stored facts gain
471
+ `Def::unwrapped`, `Def::output`, `Call::unwraps` and `Call::awaits`, so the schema version
472
+ changes and Rust indexes are rebuilt once.
473
+ - Kotlin: a class, object or interface nested in an `expect` declaration, at any depth, is
474
+ `expect` too (#437), so a use of it resolves to the `expect` one instead of staying
475
+ `ambiguous` among its `actual` declarations.
476
+ - C# `using static T` imports only the static members and nested types `T` declares (#433): a bare
477
+ `Go()` with `Go` on a base of `T` was an `exact` link to the base's method, which C# rejects
478
+ ("inherited members aren't imported"), and is now a name match at best; `using static` of the
479
+ base itself still gives it. Java's `import static` and Kotlin keep reading inherited members.
480
+ - Kotlin: a bare call resolves in Kotlin's order, an extension of the implicit receiver in scope
481
+ before a top-level function of its name (#436, from #402): inside `fun CoroutineScope.x() {
482
+ launch { } }` the call is `exact` to `CoroutineScope.launch`, not to the top-level `launch`
483
+ (`ambiguous` with it when the extension may apply to any receiver), and an `object`'s name is
484
+ its instance, so `Dispatchers.setMain(..)` reaches an imported `fun Dispatchers.setMain` (it
485
+ was no link) while a class's name keeps companion and statics. "Known ceilings" drops the
486
+ bare-call line. No golden changed.
487
+ - C#: an `internal`, `private` or `private protected` constructor or method of a public type is
488
+ a candidate from its own project's files alone (#441); `InternalsVisibleTo` stays unread.
489
+ - The console writes one `ui: directory: unreadable` stderr line per request when the directory
490
+ cannot be read (#451, after #335): the request's session remembers the failure at admission,
491
+ so the flags, the admission counts and the owner picker take that answer and write no second
492
+ line (`workspace` wrote two), and a write it refuses as 503 `audit_unavailable` prints no
493
+ pre-authentication audit line beside it. Reads still answer with the flags unavailable, the
494
+ counts null and the picker a 503; writes still refuse as before. No golden changed.
495
+ - Postgres calls that had no client-side deadline now have one (#447): a SCIM request (under the
496
+ directory's one write lock), the role check's fence read and write transaction, and the
497
+ console's start check, so a Postgres that accepts the connection and stops answering ends in a
498
+ 503, an exit 1 with no exclusions file a reader admits, and a console that starts, instead of
499
+ holding them forever. `postgres::Config::bound(n)` now adds the version check's two statements
500
+ itself and every call site counts only its own (the audit and directory reads and the overage
501
+ lookup moved accordingly; the accounts' calls, which undercounted, and the permissions poll
502
+ gained the two). No golden changed.
503
+ - A crash after the pointer swap can no longer leave `current` naming a version document that
504
+ never reached the disk (#518): the pointer, the version document `meada workspace pull` writes,
505
+ the pulled contexts file and the exclusions file are replaced through one helper
506
+ (`pull::replace`) that syncs the new file before the rename and removes `<name>.new` when a
507
+ step fails. A failed pointer rename now names `current`, not `current.new`.
508
+ - The docs say what 1.0.0 ships: nine languages (TypeScript, JavaScript, Python, Go, Rust, Java,
509
+ Kotlin, C# and Swift). The three READMEs, the three 1.0.0 release notes and the three user
510
+ guides no longer call Java, Kotlin, C# and Swift later 1.x work, the user guides gain a section
511
+ for each of the four (9.5 to 9.8) with their brokers (JMS, Azure Service Bus) and package
512
+ ecosystems (Maven and Gradle, NuGet, SwiftPM), and ADR 0003 records the change in an
513
+ amendment. No code, default dependency or golden changed.
514
+ - A server-mode mirror's `meada.toml` and `meada.decisions.toml` are read through no symbolic
515
+ link (#547, after #506), as a pulled generation's are: `mirror()`, behind `Manifest::read`
516
+ (`mcp --listen`, snapshot pull, the lock and pointer operations, workspace versions, the
517
+ heartbeat, the UI, the workspaces CLI, the GitHub App), now refuses a link unopened, one that
518
+ stays inside the mirror included, a file that is not regular and a file replaced while read,
519
+ with the generation's messages, and bounds each file at 1 MiB (`GENERATION_CONFIG_MAX`, now
520
+ built without the `snapshot` feature). A local checkout and an operator's own files still
521
+ follow links. The architecture map and the snapshots page, in its three languages, say so.
522
+ - No manifest error quotes a written value (#545), after #449 stopped serde's `invalid type` and
523
+ `invalid value`: `unknown variant` names the key and the values it accepts (`` `workspace.source`:
524
+ is not one of the values it accepts (`file`, `store`) ``) instead of serde's text, an error no
525
+ key spans reads "a value is not valid here" instead of serde's message, and the rule errors
526
+ for `serve.prefix`, `serve.strip`, `serve.documents` and a resource's `kind` name the key and
527
+ the rule (`` `serve.strip`: must start with `/` ``) instead of the value. The console's cut of
528
+ an error to its position stays as a second guard (it still covers an error built outside
529
+ `describe` that names an identity). English and pt-BR texts changed; the workspace validation
530
+ fixture changed only by the new texts.
531
+ - The deploy fetch reads a `[[repository]]` entry by its own keys (#544): any table header ends
532
+ the entry before it, so a `[[repository.peer]]` or `[[repository.resource]]` table no longer
533
+ replaces its `repo` or `path`, and a value is the text between its quotes, so a trailing
534
+ comment is not part of it. Before, such a version stopped the Compose refresh and let the chart
535
+ clone the peer's repository into the entry's path (or into a directory named after the
536
+ comment). `fetch-pulled.sh` and the chart's `workspace.fetch` carry one awk program, and a
537
+ test fails when the two copies drift. No golden changed.
538
+ - A repository identity on the `[oidc.github]` host compares without case wherever it meets the
539
+ catalog (#508): the roles job gives a selected `github.com/Acme/API` and the catalog's
540
+ `github.com/acme/api` one `both` row keyed as written, the `max_repositories` cap does not
541
+ count it as extra, and the console's catalog check and listing match it. A repository selected
542
+ in two spellings (a deployment's `github.com/Acme/API`, a named workspace's
543
+ `github.com/acme/api`) keeps one `source` row under the first and gets its role rows under
544
+ each, so grants, which match exactly, read both. Other hosts compare exactly. No golden
545
+ changed.
546
+ - Compose mirror origins (#445): `fetch.sh` and `fetch-pulled.sh` read an existing mirror's
547
+ `origin` before fetching and refuse one whose HTTP(S) URL carries credentials (a mirror cloned
548
+ from a URL with a token keeps it there), naming the identity and never the URL, and the refresh
549
+ stops before index and publish as a failed fetch does. The READMEs tell the operator to run
550
+ `git remote set-url origin <URL without credentials>` in such a mirror.
551
+ - Java and Kotlin: a file with thousands of fields and locals is read in linear time (#442, from
552
+ #424). The hides check indexes the fields by name instead of scanning every field per local,
553
+ the class around a write is found from the prefixes of its scope, and `declared_before` (and
554
+ Kotlin's `assigned`) read a node's parent from an index built once per file, since
555
+ `Node::parent()` is found from the root and made a deep file quadratic per write. Same answers;
556
+ no golden changed.
557
+ - Indexing: a file a pack drops for passing a limit is named by `meada status` (#434, from
558
+ #419). The Java, Kotlin and Swift qualified-name budget (4 MiB) now sets `Facts::budget`, as the
559
+ C# one does, instead of `unbuilt`, which prints nothing; a C# project that gives its files more
560
+ than 256 usings (`PROJECT_USINGS`) marks each of them with the new `Facts::usings`, which a new
561
+ status line names (`Msg::FileTooManyUsings`, with the count). Kotlin's `misparsed` file stayed
562
+ `unbuilt` (a grammar defect, not a limit; #546 names it too). An index built before this change keeps a Java,
563
+ Kotlin or Swift file dropped by its budget as `unbuilt` until the file changes. No limit
564
+ changed. The `cli.status-budget` goldens gained the new cases; no stored format golden changed
565
+ (the new field is absent from every sample), so the schema version is the same.
566
+ - Resolution: the receiver and call depth (`RECEIVER_DEPTH`) is one count for the whole lookup
567
+ (#432, from #417), carried through a glob, an alias or an on-demand import as the link count is,
568
+ so a chain that alternates receivers and imports costs its length, not `RECEIVER_DEPTH` per link
569
+ up to `LINK_DEPTH`. No limit changed and no answer under the limits; no golden changed.
570
+ - Helm: the default `workspace.fetch` (#444, from #316) reads the repositories from `$1` when
571
+ given (the pulled list under `modules.oidc.github`) else from `workspace.repositories`, now
572
+ mounted as `repositories.toml` so a store-sourced refresh, whose bootstrap lists none, still
573
+ fetches the operator's list, refuses a URL carrying a credential and, as the compose
574
+ scripts do (#445), an existing mirror whose `origin` carries one, keeps each mirror strictly
575
+ under `/data/mirrors`, and on failure prints `refresh: fetch failed for <identity>; the refresh
576
+ stops before publication` and exits nonzero without echoing a URL or token.
577
+ `scripts/helm-check` runs the rendered script under `sh` with a stub `git` to check these; the
578
+ chart READMEs describe it.
579
+ - Workspace import (#450): `meada workspace import` reads its file once, bounded by the version
580
+ size limit, and audits the id of the text it stored; a file past the bound or not a regular
581
+ file is refused before any audit record is written.
582
+ - Manifest type errors (#449): a `meada.toml` or workspace manifest key of the wrong type, or
583
+ with an invalid value, reports the key and the expected kind (`` `oidc.entra`: has the wrong
584
+ type (a table was expected) ``) instead of serde's message, which echoed the written value, so a
585
+ secret pasted under the wrong key no longer reaches stderr.
586
+ - Pulled generations (#506): a mirror's `meada.toml` or `meada.decisions.toml` that is a symbolic
587
+ link is refused unopened, the error naming the file, so a repository can no longer make a node
588
+ read and parse a file of the host. A link into the mirror (`meada.toml -> conf/meada.toml`) is
589
+ refused too, as the index refuses a linked pack config. The file opened is checked to be the one
590
+ checked. Secrets and CAs a manifest names still follow links (Kubernetes mounts them through
591
+ one). The snapshots page says so in its three languages.
592
+ - Named workspaces on a node (#510): a node shows a named workspace's route
593
+ (`/-/workspaces/<id>/<identity>`, pinned or not) and lists it in a 404 only to a token whose
594
+ grant reads every entry of the workspace's version, the entries the sponsor rule excluded
595
+ included, as the console does. Before, once A of a Y+A workspace lost its sponsor, a subject
596
+ reading Y alone found the workspace on a node. A generation's context now records `excluded`,
597
+ the identities the sponsor rule left out, sorted, and its digest covers them; a context without
598
+ one is written as before, with the same generation id, and a generation published earlier reads
599
+ as none excluded. A node on an older binary refuses a generation that records an exclusion, so
600
+ upgrade nodes before or with the publisher. No golden changed.
601
+
9
602
  ## [1.0.0] - 2026-10-30
10
603
 
11
604
  The tree declares `1.0.0`: this release raises the workspace, the `meada-core` pin, the Dockerfile,
@@ -704,6 +1297,8 @@ and `trace` from the two longest processes. The spec adds about 0.3 MB and 0.03
704
1297
  The rise of the single-file reindex since 2026-10-14 predates it (specs #22 and #23), and at
705
1298
  692 files it is close to its target.
706
1299
 
707
- [Unreleased]: https://github.com/ClaudioMascaro/meada/compare/v1.0.0...HEAD
1300
+ [Unreleased]: https://github.com/ClaudioMascaro/meada/compare/v1.2.0...HEAD
1301
+ [1.2.0]: https://github.com/ClaudioMascaro/meada/releases/tag/v1.2.0
1302
+ [1.1.0]: https://github.com/ClaudioMascaro/meada/releases/tag/v1.1.0
708
1303
  [1.0.0]: https://github.com/ClaudioMascaro/meada/releases/tag/v1.0.0
709
1304
  [0.1.0]: https://github.com/ClaudioMascaro/meada/releases/tag/v0.1.0
package/README.md CHANGED
@@ -18,7 +18,7 @@ Escolha a linha que combina com o que você já tem. Todos os canais entregam o
18
18
  | Rust | `cargo install meada` | `meada mcp` |
19
19
  | Linux ou macOS | o instalador de shell abaixo | `meada mcp` |
20
20
  | Qualquer sistema | o arquivo do seu sistema nas [releases do GitHub](https://github.com/ClaudioMascaro/meada/releases), com `meada` no `PATH` | `meada mcp` |
21
- | Docker | `docker pull ghcr.io/claudiomascaro/meada:1.0.0` | a linha `docker run` em [Conectar um agente](#conectar-um-agente-mcp) |
21
+ | Docker | `docker pull ghcr.io/claudiomascaro/meada:1.2.0` | a linha `docker run` em [Conectar um agente](#conectar-um-agente-mcp) |
22
22
 
23
23
  ```sh
24
24
  # Instalador de shell (Linux e macOS)
@@ -75,7 +75,7 @@ Com Docker (Linux e macOS):
75
75
  "mcpServers": {
76
76
  "meada": {
77
77
  "command": "sh",
78
- "args": ["-c", "exec docker run -i --rm --network none --user \"$(id -u):$(id -g)\" -v \"${PWD%/*}:${PWD%/*}\" -w \"$PWD\" ghcr.io/claudiomascaro/meada:1.0.0 mcp"]
78
+ "args": ["-c", "exec docker run -i --rm --network none --user \"$(id -u):$(id -g)\" -v \"${PWD%/*}:${PWD%/*}\" -w \"$PWD\" ghcr.io/claudiomascaro/meada:1.2.0 mcp"]
79
79
  }
80
80
  }
81
81
  }
@@ -97,7 +97,7 @@ ler os níveis de uma resposta. No Claude Code:
97
97
 
98
98
  ```sh
99
99
  mkdir -p ~/.claude/skills/meada
100
- curl -fsSL https://raw.githubusercontent.com/ClaudioMascaro/meada/v1.0.0/skills/meada/SKILL.md -o ~/.claude/skills/meada/SKILL.md
100
+ curl -fsSL https://raw.githubusercontent.com/ClaudioMascaro/meada/v1.2.0/skills/meada/SKILL.md -o ~/.claude/skills/meada/SKILL.md
101
101
  ```
102
102
 
103
103
  Outros agentes: veja [Agentes e MCP](https://claudiomascaro.github.io/meada/mcp/#skill-para-agentes).
@@ -111,8 +111,8 @@ Meada 1.0 entrega todo o escopo da v1 do [ADR 0003](docs/adr/0003-v1-scope-and-r
111
111
  - **Níveis**: um nível em cada ligação, cadeias que atravessam repositórios e decisões com
112
112
  decisor opcional (`meada decide`).
113
113
  - **Análises**: drift de forma, comunidades e processos.
114
- - **Linguagens no 1.0**: TypeScript e JavaScript, Python, Go e Rust. Java, Kotlin, C# e Swift
115
- são trabalho planejado da Release 2 e chegam depois como versões 1.x (#26 a #29, ADR 0003).
114
+ - **Linguagens no 1.0**: nove: TypeScript, JavaScript, Python, Go, Rust, Java, Kotlin, C# e
115
+ Swift (#26 a #29, ADR 0003).
116
116
 
117
117
  **Promessa de estabilidade.** A partir do 1.0 vale o semver: uma mudança incompatível em um
118
118
  destes itens pede uma versão major.
@@ -19,7 +19,7 @@
19
19
  "hasInstallScript": true,
20
20
  "license": "Apache-2.0",
21
21
  "name": "@meada/meada",
22
- "version": "1.0.0"
22
+ "version": "1.2.0"
23
23
  },
24
24
  "node_modules/detect-libc": {
25
25
  "engines": {
@@ -48,5 +48,5 @@
48
48
  }
49
49
  },
50
50
  "requires": true,
51
- "version": "1.0.0"
51
+ "version": "1.2.0"
52
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "artifactDownloadUrls": [
3
- "https://github.com/ClaudioMascaro/meada/releases/download/v1.0.0"
3
+ "https://github.com/ClaudioMascaro/meada/releases/download/v1.2.0"
4
4
  ],
5
5
  "bin": {
6
6
  "meada": "run-meada.js"
@@ -89,7 +89,7 @@
89
89
  "zipExt": ".tar.xz"
90
90
  }
91
91
  },
92
- "version": "1.0.0",
92
+ "version": "1.2.0",
93
93
  "volta": {
94
94
  "node": "18.14.1",
95
95
  "npm": "9.5.0"