@bongos/core 1.19.897 → 1.19.898
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/.bongos-core.json
CHANGED
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.898",
|
|
6
|
+
"core_contract": "1.19.898",
|
|
7
|
+
"source_commit": "83c5474eb902fdb151eafe46b8e71103ec8fddc3",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-20T03:57:02.228Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 501,
|
|
13
13
|
"agent_docs_stubbed": 26,
|
|
14
14
|
"functional_verbatim": 2277,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2804,
|
|
20
|
+
"tree_sha256": "81209f20e18badef8c7699d57df22d9f10d76dcb7cdb49f1f1e3bdcffdc1a8ce",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2049,10 +2049,15 @@
|
|
|
2049
2049
|
"mode": "0000644",
|
|
2050
2050
|
"sha256": "6046995188cef5e8652787eca38ccc6a69393f0985891764d6573f3379bbe6ab"
|
|
2051
2051
|
},
|
|
2052
|
+
{
|
|
2053
|
+
"path": "docs/adr/0312-provenance-is-a-second-ideas-owned-edge-table.md",
|
|
2054
|
+
"mode": "0000644",
|
|
2055
|
+
"sha256": "be07bd84a0167bbadfd3569286a5a69da403336739a88fccb5a5b6231e225af6"
|
|
2056
|
+
},
|
|
2052
2057
|
{
|
|
2053
2058
|
"path": "docs/adr/README.md",
|
|
2054
2059
|
"mode": "0000644",
|
|
2055
|
-
"sha256": "
|
|
2060
|
+
"sha256": "85666c7a834c711519264da5f88e2ff1cc950fc1d9c6038d9d0251e9ba7c9db0"
|
|
2056
2061
|
},
|
|
2057
2062
|
{
|
|
2058
2063
|
"path": "docs/api-reference.md",
|
|
@@ -2622,7 +2627,7 @@
|
|
|
2622
2627
|
{
|
|
2623
2628
|
"path": "docs/module-api-changelog.md",
|
|
2624
2629
|
"mode": "0000644",
|
|
2625
|
-
"sha256": "
|
|
2630
|
+
"sha256": "3549eff34b79f43215969e5f04c584ba107742c4c8404314105a1da6c356cfa6"
|
|
2626
2631
|
},
|
|
2627
2632
|
{
|
|
2628
2633
|
"path": "docs/modules-contract.md",
|
|
@@ -7732,12 +7737,12 @@
|
|
|
7732
7737
|
{
|
|
7733
7738
|
"path": "package-lock.json",
|
|
7734
7739
|
"mode": "0000644",
|
|
7735
|
-
"sha256": "
|
|
7740
|
+
"sha256": "e7c6f92f244fabe2e8a57f1a74f196dab668c42884b5132aa41f10317b7b6640"
|
|
7736
7741
|
},
|
|
7737
7742
|
{
|
|
7738
7743
|
"path": "package.json",
|
|
7739
7744
|
"mode": "0000644",
|
|
7740
|
-
"sha256": "
|
|
7745
|
+
"sha256": "f9d896d331e9ecea3db23ec5d58bcec8488e3dbc1c924a4a94d27dc10b1c3798"
|
|
7741
7746
|
},
|
|
7742
7747
|
{
|
|
7743
7748
|
"path": "public-docs/index.html",
|
|
@@ -9747,7 +9752,7 @@
|
|
|
9747
9752
|
{
|
|
9748
9753
|
"path": "src/module-api.js",
|
|
9749
9754
|
"mode": "0000644",
|
|
9750
|
-
"sha256": "
|
|
9755
|
+
"sha256": "cfa865647882f01bac0dbf3f653f66544a05e283895b36a8d5906b32891e2302"
|
|
9751
9756
|
},
|
|
9752
9757
|
{
|
|
9753
9758
|
"path": "src/module-loader/catalog.js",
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# ADR 0312 — Provenance is a second ideas-owned edge table, written by the seams that already know
|
|
2
|
+
|
|
3
|
+
**Status:** accepted · **Date:** 2026-09-19 · **Task:** [task 1004080](https://cloudbongos.com/builders#/task/1004080) (goal 1000095 — BONGOS-V2)
|
|
4
|
+
|
|
5
|
+
**Related:** [ADR 0311](0311-an-idea-is-a-permanent-origin-tag.md) (the origin tag this records the descent of) · [ADR 0236](0236-many-ideas-one-task-the-lineage-key-is-the-pair.md) (made co-source ideas real, which is why the edge cannot live on the lineage row) · [ADR 0083](0083-modular-architecture-strangler-build-plan.md) §Decision 5 (a module migration may only touch its own namespace) · [ADR 0054](0054-session-token-reward-cost-plus.md) (the credit the payout rides on) · [ADR 0015](0015-task-dependencies-and-auto-promotion.md)
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
A descent — `idea → task → rewrite → split → removal` — is four levels deep and crosses a version boundary. The obvious place to put it is the task hierarchy, and that place is closed.
|
|
10
|
+
|
|
11
|
+
`modules/lifecycle/hierarchy.js` `attachParent` enforces four invariants, verified by reading the code rather than the comment:
|
|
12
|
+
|
|
13
|
+
| Invariant | Error code |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `target !== parent` | `SELF_PARENT` |
|
|
16
|
+
| `target.version_id === parent.version_id` | `VERSION_MISMATCH` |
|
|
17
|
+
| `parent.parent_task_id IS NULL` (depth cap, side 1) | `PARENT_HAS_PARENT` |
|
|
18
|
+
| target has no children (depth cap, side 2) | `TARGET_HAS_CHILDREN` |
|
|
19
|
+
|
|
20
|
+
All four are deliberate; ship rollup and claim safety lean on them, and spec decision 8 puts widening them out of scope. So provenance needs its own relation.
|
|
21
|
+
|
|
22
|
+
**The spike was told to confirm `ideas_task_lineage` rather than assume it. Confirmed for one half, and refuted for the other.**
|
|
23
|
+
|
|
24
|
+
## Decision
|
|
25
|
+
|
|
26
|
+
**Two tables, not one.** `ideas_task_lineage` stays exactly as it is and anchors depth 0. A new ideas-owned table records task→task edges.
|
|
27
|
+
|
|
28
|
+
### Why the edge cannot go on `ideas_task_lineage`
|
|
29
|
+
|
|
30
|
+
The table is bipartite (ideas × tasks) with `PRIMARY KEY (task_id, idea_id)` since `ideas_006`. It carries none of the hierarchy's invariants — no depth cap, no version predicate, no self-reference hazard — so as the **idea→task anchor** it is right, and that half of the assumption holds.
|
|
31
|
+
|
|
32
|
+
But a derivation is a property of the **task pair**, not of the (task, idea) pair. Adding `derived_from_task_id` to the lineage row would write the same derivation once per co-source idea, and `ideas_006` made co-source ideas both legal and expected (merging duplicate reports into one task is the triage move the inbox is built to encourage). Two rows for one task could then disagree about where that task came from, with nothing to arbitrate. That is not a hypothetical: `ideas_006` exists precisely because an under-keyed row silently lost attribution on prod, and it took months to notice.
|
|
33
|
+
|
|
34
|
+
A merge also gives a task **several** parents, so the relation is a DAG, not a tree — a single nullable column could not express it regardless.
|
|
35
|
+
|
|
36
|
+
### The edge table
|
|
37
|
+
|
|
38
|
+
`ideas_task_descent`, in the `ideas_` namespace (ADR 0083 §5 — `tasks` belongs to the protected `lifecycle` module and may not be altered from here; a FK to it is a read, the `ideas_002` precedent).
|
|
39
|
+
|
|
40
|
+
- `task_id` → the derived task, `parent_task_id` → what it came from, both FK to `tasks`.
|
|
41
|
+
- `relation` — a CHECK'd vocabulary: `rewrite`, `split`, `merge`, `fold`, `cascade`. Extended the `ideas_003` way (drop and re-add the same-named constraint, which `isConstraintWidening` exempts), with that migration's safety net proving the widening took.
|
|
42
|
+
- `PRIMARY KEY (task_id, parent_task_id)` — a task may have several parents; one pair is recorded once.
|
|
43
|
+
- Indexed both directions: descent walks down from a parent, payout walks up from a ship.
|
|
44
|
+
|
|
45
|
+
**No depth cap and no version predicate** — that is the entire point, and it is what the hierarchy could not give.
|
|
46
|
+
|
|
47
|
+
**Cycles must be refused at write time.** The payout walks this graph, so a cycle is a non-terminating walk, not a cosmetic error. A self-edge is refused by CHECK; a longer cycle is refused by the writer, which walks to the root before inserting. The walk is also depth-bounded when read, so a cycle that somehow lands cannot hang a page.
|
|
48
|
+
|
|
49
|
+
### Who writes the edge
|
|
50
|
+
|
|
51
|
+
The task set the real question: parentage today is a manual act, so an edge that depends on someone remembering will have holes. It does not have to. **Three seams already know a task was derived, and none of them is currently telling anyone:**
|
|
52
|
+
|
|
53
|
+
| Seam | What it already records | What it becomes |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `modules/lifecycle/cascade.js` | `source_ref: cascade-<key>-<id>` — the originating task id, **encoded in a string** | `relation='cascade'`, written at creation |
|
|
56
|
+
| `tasks.merged_into_task_id` | supersede/fold provenance, CHECK'd to `abandoned` rows (`core_232`) | `relation='fold'` — the mockup's "satellite" |
|
|
57
|
+
| `tasks.parent_task_id` | the one-level split | `relation='split'` |
|
|
58
|
+
|
|
59
|
+
The cascade case is the telling one. The derivation is *already there* and already correct — it is simply stored as text inside `source_ref`, where nothing can join on it. Promoting it to an edge is not new bookkeeping, it is writing down a fact the system already computes.
|
|
60
|
+
|
|
61
|
+
That leaves `rewrite` and cross-version `merge` as genuinely manual, which is honest: those are editorial acts with no automatic signal behind them. They get an explicit write, and their absence degrades the picture rather than corrupting it.
|
|
62
|
+
|
|
63
|
+
## Consequences
|
|
64
|
+
|
|
65
|
+
**What this fixes.** `sourceIdeaForTask` (`inbox.js:870`) and `awardIdeaTaskShipCredit` (`credits.js:540`) both read `ideas_task_lineage` with `ORDER BY created_at, idea_id LIMIT 1` — a **direct, one-hop point read**. A derived task has no lineage row of its own, so today it resolves to `no_source_idea` and the origin idea is not paid at all. The descent walk is what closes that, and spec decision 6's depth decay is what keeps it from paying unboundedly.
|
|
66
|
+
|
|
67
|
+
**Two relations over the same pair of tasks now exist** — `parent_task_id` (work decomposition, capped, same-version) and this one (provenance, unbounded, cross-version). They are not redundant and must not be merged: the first answers "what is this work part of", the second "where did this work come from". The split edge is written to both, which is the only overlap.
|
|
68
|
+
|
|
69
|
+
**The display is wider than the count.** Per spec decision 7 the descent *shows* more than size *counts* — a separate thought citing an origin appears in the picture and pays nothing. The edge table carries both; the payout walk filters. Conflating them would let early filers farm the project.
|
|
70
|
+
|
|
71
|
+
**A backfill is possible and partial.** Every existing cascade task can be recovered by parsing `source_ref`, and every `merged_into_task_id` is already an edge. Historical rewrites are unrecoverable, which is consistent with spec decision 17: pre-existing ideas get lineage backfilled but not payouts, and the number must be marked as historical rather than quietly presented as a sum of payouts made.
|
|
72
|
+
|
|
73
|
+
## Alternatives rejected
|
|
74
|
+
|
|
75
|
+
- **Widen the task hierarchy.** Out of scope by spec decision 8, and the invariants are load-bearing for ship rollup and claim safety.
|
|
76
|
+
- **`derived_from_task_id` on `ideas_task_lineage`.** Duplicates the derivation per co-source idea and cannot express a merge. The reason it looks attractive — "extend, don't add" — is real, and the extension is of the lineage *ledger*, which is now two tables.
|
|
77
|
+
- **A column on `tasks`.** Forbidden from a module migration (ADR 0083 §5); `tasks` is the protected `lifecycle` module.
|
|
78
|
+
- **Derive the descent at read time from `source_ref` strings.** It covers only the cascade case, cannot express rewrite or merge, and makes a string format load-bearing for money.
|
package/docs/adr/README.md
CHANGED
|
@@ -403,3 +403,4 @@ This keeps the decision history honest and traceable.
|
|
|
403
403
|
| 0309 | [**Module enablement is a database row, above the committed pack and below env** ([task 1002857](https://cloudbongos.com/builders#/task/1002857), goal 1000091). The hall Modules-tab toggle ([ADR 0107](0107-module-upstreaming-contribution-to-core-catalog.md) §9) wrote `config/modules.json` and reloaded the cache, so it looked like it worked — but that file is the committed instance pack and the pull-deploy runs `git reset --hard origin/main`, so the toggle reverted on the next deploy, **silently**. Enablement moves to `module_enablement_overrides` (migration `core_248`), read as one precedence layer: neutral pack → instance pack → **DB override** → env → default. **Above the pack** because the pack is what a deploy restores, so an override below it would be erased by the event it exists to survive; **below env** because `<PREFIX>_MODULE_<KEY>` is the incident knob and must not need a reachable database. **Auto-committing to `main` stays rejected** ([ADR 0016](<redacted>.md)): durability belongs in the DB, not in an HTTP handler that writes to the default branch. Two open design points settled: the **scope key** is the resolved instance pack path (the only axis two instances sharing one database differ on, so one sibling's toggle cannot flip the other's module), and the DB is read into a **snapshot** refreshed at boot and on write rather than inline, because `loadModules()` is synchronous and making it async would ripple into every consumer of a module flag. An unreachable database is a **no-op** — no row means "no opinion", not "off". Does not decide: whether a toggle should also restart the process so remounting is immediate.](0309-durable-module-enablement-db-override.md) | modules / ops |
|
|
404
404
|
| 0310 | [**A speciality OFFERS skills; the adopter turns them on, one at a time, having been shown what each does** ([task 1003978](https://cloudbongos.com/builders#/task/1003978), goal 1000095). Completes [ADR 0296](0296-a-role-speciality-is-data-over-three-existing-surfaces.md), which defined a speciality as knowledge + skills + an interaction contract and shipped two of the three: `grep -i skill` across the module's schema, domain and routes returns only the header sentences describing a thing that is not there — prose asserting behaviour the code does not have, and the feature's own definition at that. Task 1003978 withheld an implementation until the authority question was answered, and the answer is the strong one: **naming a skill GRANTS NOTHING**. Skills are materialised by `claude-materialize.js` and permission is rank-gated server-side with no caching ([ADR 0016](<redacted>.md)); a speciality offers a menu, and a menu is not an entitlement. **Two layers, because one layer is the blanket the owner ruled against**: the catalog holds what a speciality OFFERS, the already-per-builder `specialities_adoptions` row holds what THIS builder turned on — so two economist ideators share a speciality's knowledge and contract and need not share one enabled skill. **The default is nothing enabled, and that is a position about LEARNING rather than a safe default**: the owner's ruling is that adoption must *walk through what comes with each* because *people need to learn the system*. A settings page of unchecked boxes satisfies the letter and defeats the intent, so the bar is a user test — a person who has finished adopting can say what each skill does. Sharing needs no new mechanism: `owner_kind` / `visibility` / `offered` / `sellable` already ship the private→project→public ladder, and skills ride it. Builds nothing; the three-task order (schema, walkthrough, injection) is filed, and the four documentation sites that claimed a shipped ingredient now say decided-not-built.](0310-a-speciality-offers-skills-and-the-adopter-chooses-them.md) | specialities / methodology |
|
|
405
405
|
| 0311 | [**An idea is a permanent origin tag, and the payout follows its descent** ([task 1004076](https://cloudbongos.com/builders#/task/1004076), goal 1000095 — BONGOS-V2). An idea today is a CONTAINER for work: it leaves `idea_inbox` when it names a goal and lives on as a task, so the better-aimed the thought the faster it vanishes from whoever had it. Reported as a small confusion — a thought filed from the hall routed into a goal, the confirmation line cleared on the next keystroke, and five minutes later the owner could not find it. The idea becomes an **immutable origin tag** instead, the only thing that can answer where a piece of work came from, and **the ideator payout follows its whole descent** rather than stopping at the earliest lineage link (`awardIdeaTaskShipCredit`), decaying by depth — full at the direct task, halving each hop — so an infinite descent is worth at most twice the direct task. That is what gives the tag teeth: if it does not survive a fork, someone does not get paid. **Size and brightness are two channels, not one number**: size is the sum of those payouts and never falls, brightness is how much of that work is still alive, so a thought whose work the project tore out renders LARGE AND DEAD rather than looking like one that never mattered. **Karma was rejected as the basis** — `karma_log` carries no task key and no idea key, deliberately ([`migrations/040_builder_karma.sql`](../../migrations/040_builder_karma.sql)), so "the karma a thought caused" is not computable; credits already are idea-attributed. **The task hierarchy is NOT widened** to carry the descent — it is capped at one level and refuses cross-version parents because ship rollup and claim safety lean on it, and provenance is a different relation from work decomposition. **Nothing records that shipped work was later removed** (`shipped` is terminal, `merged_into_task_id` is CHECK-constrained to abandoned rows), so the first `cascade.js` rule PROPOSES a removal and a person confirms it — derived-only would dim for refactors and renames, declared-only would rot. A ratified **Full Idea becomes a goal or a criterion**, carrying a recommendation the board rules on, because scope is the thing you learn last; the five questions are replaced and VERSIONED so prior filings keep their own. Dropped three tasks this invalidated and amended a fourth whose title asserted the exact exclusivity it reverses. Does not decide: the decay rate beyond its default, what precisely counts as removed, how the edges are physically recorded, or how any of it is drawn.](0311-an-idea-is-a-permanent-origin-tag.md) | ideas / economy |
|
|
406
|
+
| 0312 | [**Provenance is a SECOND ideas-owned edge table, written by the seams that already know** ([task 1004080](https://cloudbongos.com/builders#/task/1004080), goal 1000095 — BONGOS-V2). The spike [ADR 0311](0311-an-idea-is-a-permanent-origin-tag.md) deferred: how the descent edges are physically recorded. A descent (`idea → task → rewrite → split → removal`) is four levels deep and crosses a version boundary, and the task hierarchy refuses both — `attachParent` enforces `SELF_PARENT`, `VERSION_MISMATCH`, `PARENT_HAS_PARENT` and `TARGET_HAS_CHILDREN`, all load-bearing for ship rollup and claim safety. The spike was told to CONFIRM `ideas_task_lineage` rather than assume it, and confirmed one half while refuting the other: the table is right as the **idea→task anchor** (bipartite, no depth cap, no version predicate) but CANNOT carry the task→task edge, because a derivation is a property of the task PAIR and [ADR 0236](0236-many-ideas-one-task-the-lineage-key-is-the-pair.md) made co-source ideas both legal and common — a `derived_from_task_id` column would write the same derivation once per co-source idea and let two rows disagree about where a task came from, the same under-keying that silently lost attribution on prod once already. A merge also gives a task SEVERAL parents, so the relation is a **DAG, not a tree**. Decision: a new `ideas_task_descent` (`task_id`, `parent_task_id`, CHECK'd `relation`, PK on the pair, indexed both ways), with NO depth cap and NO version predicate, and **cycles refused at write time** because the payout walks this graph and a cycle is a non-terminating walk rather than a cosmetic error. On who writes it — the question the task actually set, since an edge depending on memory will have holes — **three seams already know and none is telling anyone**: `cascade.js` encodes the originating task id inside `source_ref` as a STRING nothing can join on, `tasks.merged_into_task_id` already records the fold, and `parent_task_id` already records the split. Only `rewrite` and cross-version `merge` stay manual, which is honest — they are editorial acts with no automatic signal, and their absence degrades the picture rather than corrupting it. What it fixes: `sourceIdeaForTask` and `awardIdeaTaskShipCredit` are both one-hop `LIMIT 1` point reads, so a DERIVED task resolves to `no_source_idea` and the origin is not paid at all. Does not decide: the decay rate beyond its default, what counts as removed ([task 1004081](https://cloudbongos.com/builders#/task/1004081)), or how any of it is drawn.](0312-provenance-is-a-second-ideas-owned-edge-table.md) | ideas / lifecycle |
|
|
@@ -2268,5 +2268,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2268
2268
|
landed since 1.19.895 with no explicit bump. run 35478072367. (task 1002620)
|
|
2269
2269
|
1.19.897 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2270
2270
|
landed since 1.19.896 with no explicit bump. run 35485346707. (task 1002620)
|
|
2271
|
+
1.19.898 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2272
|
+
landed since 1.19.897 with no explicit bump. run 35487863230. (task 1002620)
|
|
2271
2273
|
---------------------------------------------------------------------------
|
|
2272
2274
|
```
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.898",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.898",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.898",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
package/src/module-api.js
CHANGED
|
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
71
71
|
// there. scripts/gds/bump-version.js still rewrites the literal below; it appends
|
|
72
72
|
// the entry to that file. Look for a version's history there, not here.
|
|
73
73
|
// ---------------------------------------------------------------------------
|
|
74
|
-
const CORE_VERSION = '1.19.
|
|
74
|
+
const CORE_VERSION = '1.19.898'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
75
75
|
|
|
76
76
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
77
77
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|