@ai-matrx/alchemy 0.4.0 → 0.5.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
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0 — 2026-09-25
4
+
5
+ Adds the `/ports` entry (Matrx Alchemy ALC-13): the host port types for the ALC-13/14 waves only — `kinds` (`KindValidatorPort`, content-ir's validator injected), `diagnostics` (required), `identity` and `persistence` — gathered in `AlchemyHostPorts`, plus `Json`. Types only; no runtime code. Every optional port that a host leaves unbound means its capability is absent, never stubbed. `SchemaSourcePort` is not declared here: it is defined and exported by `@ai-matrx/content-ir/registry`.
6
+
7
+ ### Consumer action
8
+
9
+ None required. A host that mounts Alchemy may bind `AlchemyHostPorts` once at its boundary; later waves add further optional ports.
10
+
3
11
  ## 0.4.0 — 2026-09-25
4
12
 
5
13
  Alchemy now sits below `@ai-matrx/agents` (ALC-12). The `/matrx` and `/matrx/react` entries, which only re-exported `@ai-matrx/agents/content-transfer[/react]`, are removed, and `@ai-matrx/agents` is no longer a dependency.
package/README.md CHANGED
@@ -87,6 +87,7 @@ const artifact = serialize(createDraft(snapshot), "plain");
87
87
  |---|---|
88
88
  | `/core` (also package root) | Capture, projection, preparation, serializers, artifacts and transport. |
89
89
  | `/react` | `AlchemyMenu`, lower-level `ContentTransferMenu`, surface/provider bindings and React glyph. |
90
+ | `/ports` | Host port types only (`AlchemyHostPorts`, `KindValidatorPort`, `DiagnosticsPort`, `IdentityPort`, `PersistencePort`). A host binds them once at its boundary; an unbound optional port means that capability is absent, never stubbed. |
90
91
  | `/styles.css` | Self-contained menu and workspace styling. |
91
92
  | `/alchemy.svg`, `/portal.svg`, `/copy-transform.svg` | Packaged icon assets; Portal is default. |
92
93
 
package/dist/ports.cjs ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/ports.ts
17
+ var ports_exports = {};
18
+ module.exports = __toCommonJS(ports_exports);
19
+ //# sourceMappingURL=ports.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ports.ts"],"sourcesContent":["/**\n * `@ai-matrx/alchemy/ports` — the host ports (Matrx Alchemy CONTRACT §2.2).\n *\n * The app binds these ONCE, at its boundary (where the Alchemy host is\n * mounted). The package never imports the host.\n *\n * ── Ports arrive with the wave that needs them (chair ruling N8) ────────────\n *\n * This entry declares only the ports the current waves use:\n *\n * ALC-13 `kinds` (content-ir's validator, injected), `diagnostics` (required)\n * ALC-14 `identity`, `persistence`\n *\n * Later waves add store/notify/overlay/icons/knobs/i18n/auth/dialogs (ALC-15),\n * transport/assets/server (ALC-16) and approvals/bodies/receipts (ALC-17).\n *\n * ── Absent-port semantics ───────────────────────────────────────────────────\n *\n * Every port except `diagnostics` is OPTIONAL. A port the host does not bind\n * means that capability is ABSENT: the actions, formats or writes that need\n * it are not offered at all. A missing port is never stubbed, never faked\n * with a default that pretends to work, and never shown as a dead control.\n *\n * kinds absent → kind validation is absent (no value can be checked,\n * so a kind-bearing write is not offered)\n * diagnostics REQUIRED → nothing fails silently; contract breaks land here\n * identity absent → organization-scoped declarations are absent\n * persistence absent → per-person settings are absent (organization and\n * platform defaults apply)\n *\n * Types only: this entry has no runtime code.\n */\n\n/** JSON as it crosses a port. */\nexport type Json =\n | null\n | boolean\n | number\n | string\n | Json[]\n | { [key: string]: Json };\n\n/**\n * content-ir's kind validator, injected so Alchemy validates without\n * importing the app or the kind catalog. The host builds it from\n * `@ai-matrx/content-ir`'s `createKindValidator` over its own\n * `SchemaSourcePort` (which content-ir defines and exports; Alchemy never\n * declares it).\n *\n * `unverifiable: true` marks a verdict where the kind could not be checked\n * (not registered, no schema, uncompilable schema, catalog unreachable) — a\n * skip, which is never a pass.\n */\nexport interface KindValidatorPort {\n validate(\n kindKey: string,\n value: unknown,\n signal: AbortSignal,\n ): Promise<\n | { ok: true }\n | { ok: false; sentence: string; remedy: string; unverifiable?: true }\n >;\n}\n\n/** Where contract breaks are captured. Required: nothing fails silently. */\nexport interface DiagnosticsPort {\n capture(\n error: unknown,\n context: {\n area: \"declare\" | \"operate\" | \"write\" | \"actions\" | \"menu\";\n detail: Json;\n },\n ): void;\n}\n\n/** Who is using the app right now, and in which organization. */\nexport interface IdentityPort {\n /** `null` while the host has no resolved identity yet. */\n current(): {\n userId: string;\n organizationId: string | null;\n isAuthenticated: boolean;\n isAdmin: boolean;\n } | null;\n /** Called whenever `current()` may answer differently; returns unsubscribe. */\n onChange(listener: () => void): () => void;\n}\n\n/** Per-person settings (layout, density, transfer preferences), layered by the host's settings system. */\nexport interface PersistencePort {\n readSetting<T extends Json>(key: string): Promise<T | null>;\n writeSetting(key: string, value: Json): Promise<void>;\n}\n\n/** The ports a host binds. Optional = absent capability when unbound (see above). */\nexport interface AlchemyHostPorts {\n // ALC-13\n kinds?: KindValidatorPort;\n /** REQUIRED from ALC-13 (the only non-optional port): contract breaks are captured here. */\n diagnostics: DiagnosticsPort;\n // ALC-14\n identity?: IdentityPort;\n persistence?: PersistencePort;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * `@ai-matrx/alchemy/ports` — the host ports (Matrx Alchemy CONTRACT §2.2).
3
+ *
4
+ * The app binds these ONCE, at its boundary (where the Alchemy host is
5
+ * mounted). The package never imports the host.
6
+ *
7
+ * ── Ports arrive with the wave that needs them (chair ruling N8) ────────────
8
+ *
9
+ * This entry declares only the ports the current waves use:
10
+ *
11
+ * ALC-13 `kinds` (content-ir's validator, injected), `diagnostics` (required)
12
+ * ALC-14 `identity`, `persistence`
13
+ *
14
+ * Later waves add store/notify/overlay/icons/knobs/i18n/auth/dialogs (ALC-15),
15
+ * transport/assets/server (ALC-16) and approvals/bodies/receipts (ALC-17).
16
+ *
17
+ * ── Absent-port semantics ───────────────────────────────────────────────────
18
+ *
19
+ * Every port except `diagnostics` is OPTIONAL. A port the host does not bind
20
+ * means that capability is ABSENT: the actions, formats or writes that need
21
+ * it are not offered at all. A missing port is never stubbed, never faked
22
+ * with a default that pretends to work, and never shown as a dead control.
23
+ *
24
+ * kinds absent → kind validation is absent (no value can be checked,
25
+ * so a kind-bearing write is not offered)
26
+ * diagnostics REQUIRED → nothing fails silently; contract breaks land here
27
+ * identity absent → organization-scoped declarations are absent
28
+ * persistence absent → per-person settings are absent (organization and
29
+ * platform defaults apply)
30
+ *
31
+ * Types only: this entry has no runtime code.
32
+ */
33
+ /** JSON as it crosses a port. */
34
+ type Json = null | boolean | number | string | Json[] | {
35
+ [key: string]: Json;
36
+ };
37
+ /**
38
+ * content-ir's kind validator, injected so Alchemy validates without
39
+ * importing the app or the kind catalog. The host builds it from
40
+ * `@ai-matrx/content-ir`'s `createKindValidator` over its own
41
+ * `SchemaSourcePort` (which content-ir defines and exports; Alchemy never
42
+ * declares it).
43
+ *
44
+ * `unverifiable: true` marks a verdict where the kind could not be checked
45
+ * (not registered, no schema, uncompilable schema, catalog unreachable) — a
46
+ * skip, which is never a pass.
47
+ */
48
+ interface KindValidatorPort {
49
+ validate(kindKey: string, value: unknown, signal: AbortSignal): Promise<{
50
+ ok: true;
51
+ } | {
52
+ ok: false;
53
+ sentence: string;
54
+ remedy: string;
55
+ unverifiable?: true;
56
+ }>;
57
+ }
58
+ /** Where contract breaks are captured. Required: nothing fails silently. */
59
+ interface DiagnosticsPort {
60
+ capture(error: unknown, context: {
61
+ area: "declare" | "operate" | "write" | "actions" | "menu";
62
+ detail: Json;
63
+ }): void;
64
+ }
65
+ /** Who is using the app right now, and in which organization. */
66
+ interface IdentityPort {
67
+ /** `null` while the host has no resolved identity yet. */
68
+ current(): {
69
+ userId: string;
70
+ organizationId: string | null;
71
+ isAuthenticated: boolean;
72
+ isAdmin: boolean;
73
+ } | null;
74
+ /** Called whenever `current()` may answer differently; returns unsubscribe. */
75
+ onChange(listener: () => void): () => void;
76
+ }
77
+ /** Per-person settings (layout, density, transfer preferences), layered by the host's settings system. */
78
+ interface PersistencePort {
79
+ readSetting<T extends Json>(key: string): Promise<T | null>;
80
+ writeSetting(key: string, value: Json): Promise<void>;
81
+ }
82
+ /** The ports a host binds. Optional = absent capability when unbound (see above). */
83
+ interface AlchemyHostPorts {
84
+ kinds?: KindValidatorPort;
85
+ /** REQUIRED from ALC-13 (the only non-optional port): contract breaks are captured here. */
86
+ diagnostics: DiagnosticsPort;
87
+ identity?: IdentityPort;
88
+ persistence?: PersistencePort;
89
+ }
90
+
91
+ export type { AlchemyHostPorts, DiagnosticsPort, IdentityPort, Json, KindValidatorPort, PersistencePort };
@@ -0,0 +1,91 @@
1
+ /**
2
+ * `@ai-matrx/alchemy/ports` — the host ports (Matrx Alchemy CONTRACT §2.2).
3
+ *
4
+ * The app binds these ONCE, at its boundary (where the Alchemy host is
5
+ * mounted). The package never imports the host.
6
+ *
7
+ * ── Ports arrive with the wave that needs them (chair ruling N8) ────────────
8
+ *
9
+ * This entry declares only the ports the current waves use:
10
+ *
11
+ * ALC-13 `kinds` (content-ir's validator, injected), `diagnostics` (required)
12
+ * ALC-14 `identity`, `persistence`
13
+ *
14
+ * Later waves add store/notify/overlay/icons/knobs/i18n/auth/dialogs (ALC-15),
15
+ * transport/assets/server (ALC-16) and approvals/bodies/receipts (ALC-17).
16
+ *
17
+ * ── Absent-port semantics ───────────────────────────────────────────────────
18
+ *
19
+ * Every port except `diagnostics` is OPTIONAL. A port the host does not bind
20
+ * means that capability is ABSENT: the actions, formats or writes that need
21
+ * it are not offered at all. A missing port is never stubbed, never faked
22
+ * with a default that pretends to work, and never shown as a dead control.
23
+ *
24
+ * kinds absent → kind validation is absent (no value can be checked,
25
+ * so a kind-bearing write is not offered)
26
+ * diagnostics REQUIRED → nothing fails silently; contract breaks land here
27
+ * identity absent → organization-scoped declarations are absent
28
+ * persistence absent → per-person settings are absent (organization and
29
+ * platform defaults apply)
30
+ *
31
+ * Types only: this entry has no runtime code.
32
+ */
33
+ /** JSON as it crosses a port. */
34
+ type Json = null | boolean | number | string | Json[] | {
35
+ [key: string]: Json;
36
+ };
37
+ /**
38
+ * content-ir's kind validator, injected so Alchemy validates without
39
+ * importing the app or the kind catalog. The host builds it from
40
+ * `@ai-matrx/content-ir`'s `createKindValidator` over its own
41
+ * `SchemaSourcePort` (which content-ir defines and exports; Alchemy never
42
+ * declares it).
43
+ *
44
+ * `unverifiable: true` marks a verdict where the kind could not be checked
45
+ * (not registered, no schema, uncompilable schema, catalog unreachable) — a
46
+ * skip, which is never a pass.
47
+ */
48
+ interface KindValidatorPort {
49
+ validate(kindKey: string, value: unknown, signal: AbortSignal): Promise<{
50
+ ok: true;
51
+ } | {
52
+ ok: false;
53
+ sentence: string;
54
+ remedy: string;
55
+ unverifiable?: true;
56
+ }>;
57
+ }
58
+ /** Where contract breaks are captured. Required: nothing fails silently. */
59
+ interface DiagnosticsPort {
60
+ capture(error: unknown, context: {
61
+ area: "declare" | "operate" | "write" | "actions" | "menu";
62
+ detail: Json;
63
+ }): void;
64
+ }
65
+ /** Who is using the app right now, and in which organization. */
66
+ interface IdentityPort {
67
+ /** `null` while the host has no resolved identity yet. */
68
+ current(): {
69
+ userId: string;
70
+ organizationId: string | null;
71
+ isAuthenticated: boolean;
72
+ isAdmin: boolean;
73
+ } | null;
74
+ /** Called whenever `current()` may answer differently; returns unsubscribe. */
75
+ onChange(listener: () => void): () => void;
76
+ }
77
+ /** Per-person settings (layout, density, transfer preferences), layered by the host's settings system. */
78
+ interface PersistencePort {
79
+ readSetting<T extends Json>(key: string): Promise<T | null>;
80
+ writeSetting(key: string, value: Json): Promise<void>;
81
+ }
82
+ /** The ports a host binds. Optional = absent capability when unbound (see above). */
83
+ interface AlchemyHostPorts {
84
+ kinds?: KindValidatorPort;
85
+ /** REQUIRED from ALC-13 (the only non-optional port): contract breaks are captured here. */
86
+ diagnostics: DiagnosticsPort;
87
+ identity?: IdentityPort;
88
+ persistence?: PersistencePort;
89
+ }
90
+
91
+ export type { AlchemyHostPorts, DiagnosticsPort, IdentityPort, Json, KindValidatorPort, PersistencePort };
package/dist/ports.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-matrx/alchemy",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Matrx Alchemy: the complete Matrx copy, prepare-for-AI, and export experience, with framework-neutral core, React menu, glyph and styles.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -68,6 +68,16 @@
68
68
  "default": "./dist/react.cjs"
69
69
  }
70
70
  },
71
+ "./ports": {
72
+ "import": {
73
+ "types": "./dist/ports.d.ts",
74
+ "default": "./dist/ports.js"
75
+ },
76
+ "require": {
77
+ "types": "./dist/ports.d.cts",
78
+ "default": "./dist/ports.cjs"
79
+ }
80
+ },
71
81
  "./styles.css": "./dist/styles.css",
72
82
  "./tap-target.css": "./dist/tap-target.css",
73
83
  "./alchemy.svg": "./dist/alchemy.svg",