cotal-ai 0.108.1 → 0.109.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/dist/run.js CHANGED
@@ -5,34 +5,59 @@
5
5
  * (@cotal-ai/manager). The root just picks which surfaces to pull in; `runCli` resolves
6
6
  * whatever registered. A new surface (another connector, a control client …) is one more import line.
7
7
  *
8
+ * A daemon entry is the exception: it runs one command for the life of its process, so it imports
9
+ * only the surfaces that command needs (see the providers below), never the whole CLI.
10
+ *
8
11
  * Reached only via ./cotal.ts, which runs the Node-version preflight first: everything imported
9
12
  * here requires Node >= 22 (the UI stack and the bundled nats-server optional dep), so this module
10
13
  * must never be the executable entry — importing it on an old Node crashes at parse time.
11
14
  */
12
- // NOTE: registration order across these imports is NOT guaranteed (tsx's entry interop can
13
- // evaluate the smaller daemon graphs first) — display order is a non-goal here; `help` ranks
14
- // its groups explicitly (GROUP_ORDER in @cotal-ai/cli).
15
- import { runCli, stdoutError } from "@cotal-ai/cli"; // self-registers the base surface incl. spawn (foreground + --detach) / stop / ps / attach
16
- import "@cotal-ai/manager"; // self-registers `supervise` — the agent-supervisor daemon
17
- import "@cotal-ai/delivery"; // self-registers `deliver` — the server-side Plane-3 delivery daemon
18
- import "@cotal-ai/runtime"; // self-registers `run` — the workflow-run operator surface (start/resume/ps/journal/answer)
19
- import "@cotal-ai/auth"; // self-registers login / logout — per-user IdP sessions (device-code sign-in)
20
- import "./docs.js"; // self-registers `docs`; the docs bundle loads only when `docs` runs
21
- import "./daemon/command.js"; // self-registers `daemon`: the local machine daemon's authenticated control endpoint (Linux)
22
- // Self-registers the `ag-ui.frame` part renderer, so `cotal console` and `cotal join` draw an event
23
- // frame instead of `[unrenderable part kind "ag-ui.frame"]`.
24
- //
25
- // IMPORTED HERE BECAUSE NOTHING ELSE IN THIS PROCESS WOULD. The four agent connectors are removable
26
- // ext plugins materialized lazily by `runCli`, and no `implementations/*` package imports
27
- // connector-core at runtime — measured, not assumed. So a renderer that only registered inside the
28
- // connector would be absent from every process that RENDERS, which is the one place it is needed.
29
- // The seam is worth nothing if the provider never loads at the display site.
30
- //
31
- // The narrow subpath rather than the package root, deliberately: the root pulls the MCP server
32
- // runtime and its zod copy into CLI startup, and a renderer needs none of it.
33
- import "@cotal-ai/connector-core/agui-render";
34
15
  import { registry } from "@cotal-ai/core";
35
16
  import { handOverStartupInterrupt, releaseStartupInterrupt } from "./startup-interrupt.js";
17
+ // Each surface self-registers when imported. The whole CLI imports them one after another in this
18
+ // order, which is the order the root's static imports evaluated them in; display order is still a
19
+ // non-goal, since `help` ranks its groups explicitly (GROUP_ORDER in @cotal-ai/cli).
20
+ const surfaces = {
21
+ cli: () => import("@cotal-ai/cli"), // the base surface incl. spawn (foreground + --detach) / stop / ps / attach
22
+ manager: () => import("@cotal-ai/manager"), // `supervise` — the agent-supervisor daemon
23
+ delivery: () => import("@cotal-ai/delivery"), // `deliver` — the server-side Plane-3 delivery daemon
24
+ runtime: () => import("@cotal-ai/runtime"), // `run` — the workflow-run operator surface (start/resume/ps/journal/answer)
25
+ auth: () => import("@cotal-ai/auth"), // login / logout — per-user IdP sessions (device-code sign-in)
26
+ docs: () => import("./docs.js"), // `docs`; the docs bundle loads only when `docs` runs
27
+ daemon: () => import("./daemon/command.js"), // `daemon`: the local machine daemon's authenticated control endpoint (Linux)
28
+ // The `ag-ui.frame` part renderer, so `cotal console` and `cotal join` draw an event frame instead
29
+ // of `[unrenderable part kind "ag-ui.frame"]`.
30
+ //
31
+ // IMPORTED HERE BECAUSE NOTHING ELSE IN THIS PROCESS WOULD. The four agent connectors are removable
32
+ // ext plugins materialized lazily by `runCli`, and no `implementations/*` package imports
33
+ // connector-core at runtime — measured, not assumed. So a renderer that only registered inside the
34
+ // connector would be absent from every process that RENDERS, which is the one place it is needed.
35
+ // The seam is worth nothing if the provider never loads at the display site.
36
+ //
37
+ // The narrow subpath rather than the package root, deliberately: the root pulls the MCP server
38
+ // runtime and its zod copy into CLI startup, and a renderer needs none of it.
39
+ aguiRender: () => import("@cotal-ai/connector-core/agui-render"),
40
+ };
41
+ const importing = (...names) => async () => { for (const name of names)
42
+ await surfaces[name](); };
43
+ const commands = (...names) => names.map((name) => ({ kind: "command", name }));
44
+ // The daemon entries. Each imports its own surface and the surfaces whose registrations its run
45
+ // resolves: the auth provider a user-auth mesh dials through (@cotal-ai/auth), and the workflow run
46
+ // host a manager hosts runs with (@cotal-ai/runtime). Nothing else in the CLI is imported, and the
47
+ // command's flags, refusals and exit are `runCli`'s as for any other command.
48
+ registry.provide({ provides: commands("supervise", "__daemon-manager", "__service-manager"), load: importing("manager", "auth", "runtime") });
49
+ registry.provide({ provides: commands("deliver", "__daemon-deliver", "__service-delivery", "feedback-intake", "__service-feedback-intake"), load: importing("delivery", "auth") });
50
+ registry.provide({ provides: commands("auth-service", "__daemon-auth-service", "__service-auth"), load: importing("auth") });
51
+ registry.provide({ provides: commands("__service-unit"), load: () => import("@cotal-ai/cli/service-unit") });
52
+ // The dispatch module reads the command word as `runCli` will, and loads no command. A word a
53
+ // provider declares imports that provider's surfaces; any other word imports them all.
54
+ const { commandWord, runCli, stdoutError } = await import("@cotal-ai/cli/dispatch");
55
+ const argv = process.argv.slice(2);
56
+ const word = commandWord(argv);
57
+ if (word !== undefined && registry.provides("command", word))
58
+ await registry.load("command", word);
59
+ else
60
+ await importing(...Object.keys(surfaces))();
36
61
  // A CLI must exit quietly when its stdout is closed early — piped to `head`, a pager that quits,
37
62
  // or a shell's process substitution (`source <(cotal completion script bash)`). Node otherwise turns the
38
63
  // closed-pipe write into a fatal unhandled 'error' event with a stack trace. Mirror SIGPIPE: exit
@@ -49,5 +74,4 @@ process.stdout.on("error", stdoutError);
49
74
  // the ONE composition root that loads operator-installed extensions (`cotal ext add …`) — commands,
50
75
  // runtimes, connectors, and local process components all self-register from those packages. Library
51
76
  // roots keep the explicit-import model.
52
- const argv = process.argv.slice(2);
53
77
  await runCli(registry, argv, { extensions: true, startupNotice: { release: releaseStartupInterrupt, handOver: handOverStartupInterrupt } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cotal-ai",
3
- "version": "0.108.1",
3
+ "version": "0.109.0",
4
4
  "description": "Cotal — lateral agent coordination over NATS. Run `npx cotal-ai` for the CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -33,26 +33,26 @@
33
33
  "node": ">=22"
34
34
  },
35
35
  "dependencies": {
36
- "@cotal-ai/auth": "0.108.1",
37
- "@cotal-ai/cli": "0.108.1",
38
- "@cotal-ai/connector-core": "0.108.1",
39
- "@cotal-ai/core": "0.108.1",
40
- "@cotal-ai/delivery": "0.108.1",
41
- "@cotal-ai/manager": "0.108.1",
42
- "@cotal-ai/runtime": "0.108.1",
43
- "@cotal-ai/seat": "0.108.1",
44
- "@cotal-ai/workspace": "0.108.1"
36
+ "@cotal-ai/auth": "0.109.0",
37
+ "@cotal-ai/cli": "0.109.0",
38
+ "@cotal-ai/connector-core": "0.109.0",
39
+ "@cotal-ai/core": "0.109.0",
40
+ "@cotal-ai/delivery": "0.109.0",
41
+ "@cotal-ai/manager": "0.109.0",
42
+ "@cotal-ai/runtime": "0.109.0",
43
+ "@cotal-ai/seat": "0.109.0",
44
+ "@cotal-ai/workspace": "0.109.0"
45
45
  },
46
46
  "devDependencies": {
47
- "@cotal-ai/connector-claude-code": "0.108.1",
48
- "@cotal-ai/connector-codex": "0.108.1",
49
- "@cotal-ai/connector-hermes": "0.108.1",
50
- "@cotal-ai/connector-jcode": "0.108.1",
51
- "@cotal-ai/connector-opencode": "0.108.1",
52
- "@cotal-ai/linear": "0.108.1",
53
- "@cotal-ai/pi": "0.108.1",
47
+ "@cotal-ai/connector-claude-code": "0.109.0",
48
+ "@cotal-ai/connector-codex": "0.109.0",
49
+ "@cotal-ai/connector-hermes": "0.109.0",
50
+ "@cotal-ai/connector-jcode": "0.109.0",
51
+ "@cotal-ai/connector-opencode": "0.109.0",
52
+ "@cotal-ai/linear": "0.109.0",
53
+ "@cotal-ai/pi": "0.109.0",
54
54
  "@cotal-ai/smoke-kit": "0.0.0",
55
- "@cotal-ai/web": "0.108.1",
55
+ "@cotal-ai/web": "0.109.0",
56
56
  "@nats-io/jetstream": "^3.4.0",
57
57
  "@nats-io/transport-node": "^3.4.0",
58
58
  "typescript": "^5.9.3"
@@ -69031,6 +69031,8 @@ function claims(ext) {
69031
69031
  }
69032
69032
  var Registry = class {
69033
69033
  #byKey = /* @__PURE__ */ new Map();
69034
+ /** `kind:name` → the declared provider that registers it, and its import once one has started. */
69035
+ #providers = /* @__PURE__ */ new Map();
69034
69036
  /** `kind:alias` → the claiming extension's `kind:name` key, for committed extensions. */
69035
69037
  #aliases = /* @__PURE__ */ new Map();
69036
69038
  /** While a stage is active in the CURRENT async context, {@link register} writes there instead of
@@ -69117,13 +69119,47 @@ var Registry = class {
69117
69119
  return this.#aliases.get(key) ?? key;
69118
69120
  }
69119
69121
  /** Resolve one extension by kind + name or alias. Unknown throws. Staged (uncommitted) registrations are
69120
- * invisible here; only committed ones resolve. */
69122
+ * invisible here; only committed ones resolve. A key whose declared provider has not loaded throws
69123
+ * too, naming that: {@link load} resolves it. */
69121
69124
  resolve(kind, name) {
69122
69125
  const ext = this.#byKey.get(this.#canonical(kind, name));
69123
- if (!ext)
69126
+ if (!ext) {
69127
+ if (this.#providers.has(`${kind}:${name}`))
69128
+ throw new Error(`${kind} "${name}" is declared by a provider this process has not loaded`);
69124
69129
  throw new Error(`no ${kind} registered for "${name}"`);
69130
+ }
69125
69131
  return ext;
69126
69132
  }
69133
+ /** Declare a provider: a module that registers `provides` when it is imported. Nothing is imported
69134
+ * here. A key that another provider already declares is refused, so a key has one provider. */
69135
+ provide(provider) {
69136
+ const keys = provider.provides.map((ref) => `${ref.kind}:${ref.name}`);
69137
+ for (const key of keys)
69138
+ if (this.#providers.has(key))
69139
+ throw new Error(`extension provider already declared: ${key}`);
69140
+ const entry = { provider };
69141
+ for (const key of keys)
69142
+ this.#providers.set(key, entry);
69143
+ }
69144
+ /** Whether a provider was declared for exactly this kind + name, loaded or not. A boolean probe
69145
+ * that never throws and imports nothing. */
69146
+ provides(kind, name) {
69147
+ return this.#providers.has(`${kind}:${name}`);
69148
+ }
69149
+ /** Resolve kind + name, first importing the provider declared for it unless that import has run.
69150
+ * Concurrent calls share one import. A key no provider declares resolves as {@link resolve} does.
69151
+ * A provider that loads without registering the key it declared throws: the declaration is wrong,
69152
+ * and no other extension stands in for it. */
69153
+ async load(kind, name) {
69154
+ const entry = this.#providers.get(`${kind}:${name}`);
69155
+ if (entry) {
69156
+ entry.loading ??= entry.provider.load();
69157
+ await entry.loading;
69158
+ if (!this.#byKey.has(this.#canonical(kind, name)))
69159
+ throw new Error(`the provider declared for ${kind} "${name}" loaded without registering it`);
69160
+ }
69161
+ return this.resolve(kind, name);
69162
+ }
69127
69163
  all(kind) {
69128
69164
  const values = [...this.#byKey.values()];
69129
69165
  return kind === void 0 ? values : values.filter((e) => e.kind === kind);
@@ -75492,10 +75528,10 @@ async function submitFeedback(input, options = {}) {
75492
75528
  var import_node_child_process3 = require("node:child_process");
75493
75529
 
75494
75530
  // ../connector-core/dist/docs-bundle.generated.js
75495
- var DOCS_VERSION = "0.108.1";
75531
+ var DOCS_VERSION = "0.109.0";
75496
75532
  function loadDocsBundle() {
75497
75533
  return {
75498
- "version": "0.108.1",
75534
+ "version": "0.109.0",
75499
75535
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
75500
75536
  "pages": [
75501
75537
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/connector-claude-code",
3
3
  "description": "Cotal connector for Claude Code: an installed plugin that joins a session to the mesh.",
4
- "version": "0.108.1",
4
+ "version": "0.109.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -48755,6 +48755,8 @@ function claims(ext) {
48755
48755
  }
48756
48756
  var Registry = class {
48757
48757
  #byKey = /* @__PURE__ */ new Map();
48758
+ /** `kind:name` → the declared provider that registers it, and its import once one has started. */
48759
+ #providers = /* @__PURE__ */ new Map();
48758
48760
  /** `kind:alias` → the claiming extension's `kind:name` key, for committed extensions. */
48759
48761
  #aliases = /* @__PURE__ */ new Map();
48760
48762
  /** While a stage is active in the CURRENT async context, {@link register} writes there instead of
@@ -48841,13 +48843,47 @@ var Registry = class {
48841
48843
  return this.#aliases.get(key) ?? key;
48842
48844
  }
48843
48845
  /** Resolve one extension by kind + name or alias. Unknown throws. Staged (uncommitted) registrations are
48844
- * invisible here; only committed ones resolve. */
48846
+ * invisible here; only committed ones resolve. A key whose declared provider has not loaded throws
48847
+ * too, naming that: {@link load} resolves it. */
48845
48848
  resolve(kind, name) {
48846
48849
  const ext = this.#byKey.get(this.#canonical(kind, name));
48847
- if (!ext)
48850
+ if (!ext) {
48851
+ if (this.#providers.has(`${kind}:${name}`))
48852
+ throw new Error(`${kind} "${name}" is declared by a provider this process has not loaded`);
48848
48853
  throw new Error(`no ${kind} registered for "${name}"`);
48854
+ }
48849
48855
  return ext;
48850
48856
  }
48857
+ /** Declare a provider: a module that registers `provides` when it is imported. Nothing is imported
48858
+ * here. A key that another provider already declares is refused, so a key has one provider. */
48859
+ provide(provider) {
48860
+ const keys = provider.provides.map((ref) => `${ref.kind}:${ref.name}`);
48861
+ for (const key of keys)
48862
+ if (this.#providers.has(key))
48863
+ throw new Error(`extension provider already declared: ${key}`);
48864
+ const entry = { provider };
48865
+ for (const key of keys)
48866
+ this.#providers.set(key, entry);
48867
+ }
48868
+ /** Whether a provider was declared for exactly this kind + name, loaded or not. A boolean probe
48869
+ * that never throws and imports nothing. */
48870
+ provides(kind, name) {
48871
+ return this.#providers.has(`${kind}:${name}`);
48872
+ }
48873
+ /** Resolve kind + name, first importing the provider declared for it unless that import has run.
48874
+ * Concurrent calls share one import. A key no provider declares resolves as {@link resolve} does.
48875
+ * A provider that loads without registering the key it declared throws: the declaration is wrong,
48876
+ * and no other extension stands in for it. */
48877
+ async load(kind, name) {
48878
+ const entry = this.#providers.get(`${kind}:${name}`);
48879
+ if (entry) {
48880
+ entry.loading ??= entry.provider.load();
48881
+ await entry.loading;
48882
+ if (!this.#byKey.has(this.#canonical(kind, name)))
48883
+ throw new Error(`the provider declared for ${kind} "${name}" loaded without registering it`);
48884
+ }
48885
+ return this.resolve(kind, name);
48886
+ }
48851
48887
  all(kind) {
48852
48888
  const values = [...this.#byKey.values()];
48853
48889
  return kind === void 0 ? values : values.filter((e) => e.kind === kind);
@@ -69582,10 +69618,10 @@ function date4(params) {
69582
69618
  config(en_default());
69583
69619
 
69584
69620
  // ../connector-core/dist/docs-bundle.generated.js
69585
- var DOCS_VERSION = "0.108.1";
69621
+ var DOCS_VERSION = "0.109.0";
69586
69622
  function loadDocsBundle() {
69587
69623
  return {
69588
- "version": "0.108.1",
69624
+ "version": "0.109.0",
69589
69625
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
69590
69626
  "pages": [
69591
69627
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/connector-codex",
3
3
  "description": "Cotal connector for OpenAI Codex: a host-mode peer driving codex app-server, with Codex's own TUI attached and the cotal_* tools served over a loopback MCP endpoint.",
4
- "version": "0.108.1",
4
+ "version": "0.109.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -45077,6 +45077,8 @@ function claims(ext) {
45077
45077
  }
45078
45078
  var Registry = class {
45079
45079
  #byKey = /* @__PURE__ */ new Map();
45080
+ /** `kind:name` → the declared provider that registers it, and its import once one has started. */
45081
+ #providers = /* @__PURE__ */ new Map();
45080
45082
  /** `kind:alias` → the claiming extension's `kind:name` key, for committed extensions. */
45081
45083
  #aliases = /* @__PURE__ */ new Map();
45082
45084
  /** While a stage is active in the CURRENT async context, {@link register} writes there instead of
@@ -45163,13 +45165,47 @@ var Registry = class {
45163
45165
  return this.#aliases.get(key) ?? key;
45164
45166
  }
45165
45167
  /** Resolve one extension by kind + name or alias. Unknown throws. Staged (uncommitted) registrations are
45166
- * invisible here; only committed ones resolve. */
45168
+ * invisible here; only committed ones resolve. A key whose declared provider has not loaded throws
45169
+ * too, naming that: {@link load} resolves it. */
45167
45170
  resolve(kind, name) {
45168
45171
  const ext = this.#byKey.get(this.#canonical(kind, name));
45169
- if (!ext)
45172
+ if (!ext) {
45173
+ if (this.#providers.has(`${kind}:${name}`))
45174
+ throw new Error(`${kind} "${name}" is declared by a provider this process has not loaded`);
45170
45175
  throw new Error(`no ${kind} registered for "${name}"`);
45176
+ }
45171
45177
  return ext;
45172
45178
  }
45179
+ /** Declare a provider: a module that registers `provides` when it is imported. Nothing is imported
45180
+ * here. A key that another provider already declares is refused, so a key has one provider. */
45181
+ provide(provider) {
45182
+ const keys = provider.provides.map((ref) => `${ref.kind}:${ref.name}`);
45183
+ for (const key of keys)
45184
+ if (this.#providers.has(key))
45185
+ throw new Error(`extension provider already declared: ${key}`);
45186
+ const entry = { provider };
45187
+ for (const key of keys)
45188
+ this.#providers.set(key, entry);
45189
+ }
45190
+ /** Whether a provider was declared for exactly this kind + name, loaded or not. A boolean probe
45191
+ * that never throws and imports nothing. */
45192
+ provides(kind, name) {
45193
+ return this.#providers.has(`${kind}:${name}`);
45194
+ }
45195
+ /** Resolve kind + name, first importing the provider declared for it unless that import has run.
45196
+ * Concurrent calls share one import. A key no provider declares resolves as {@link resolve} does.
45197
+ * A provider that loads without registering the key it declared throws: the declaration is wrong,
45198
+ * and no other extension stands in for it. */
45199
+ async load(kind, name) {
45200
+ const entry = this.#providers.get(`${kind}:${name}`);
45201
+ if (entry) {
45202
+ entry.loading ??= entry.provider.load();
45203
+ await entry.loading;
45204
+ if (!this.#byKey.has(this.#canonical(kind, name)))
45205
+ throw new Error(`the provider declared for ${kind} "${name}" loaded without registering it`);
45206
+ }
45207
+ return this.resolve(kind, name);
45208
+ }
45173
45209
  all(kind) {
45174
45210
  const values = [...this.#byKey.values()];
45175
45211
  return kind === void 0 ? values : values.filter((e) => e.kind === kind);
@@ -63240,10 +63276,10 @@ function date4(params) {
63240
63276
  config(en_default());
63241
63277
 
63242
63278
  // ../connector-core/dist/docs-bundle.generated.js
63243
- var DOCS_VERSION = "0.108.1";
63279
+ var DOCS_VERSION = "0.109.0";
63244
63280
  function loadDocsBundle() {
63245
63281
  return {
63246
- "version": "0.108.1",
63282
+ "version": "0.109.0",
63247
63283
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
63248
63284
  "pages": [
63249
63285
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/connector-hermes",
3
3
  "description": "Cotal connector for the Hermes (Nous Research) agent.",
4
- "version": "0.108.1",
4
+ "version": "0.109.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -44934,6 +44934,8 @@ function claims(ext) {
44934
44934
  }
44935
44935
  var Registry = class {
44936
44936
  #byKey = /* @__PURE__ */ new Map();
44937
+ /** `kind:name` → the declared provider that registers it, and its import once one has started. */
44938
+ #providers = /* @__PURE__ */ new Map();
44937
44939
  /** `kind:alias` → the claiming extension's `kind:name` key, for committed extensions. */
44938
44940
  #aliases = /* @__PURE__ */ new Map();
44939
44941
  /** While a stage is active in the CURRENT async context, {@link register} writes there instead of
@@ -45020,13 +45022,47 @@ var Registry = class {
45020
45022
  return this.#aliases.get(key) ?? key;
45021
45023
  }
45022
45024
  /** Resolve one extension by kind + name or alias. Unknown throws. Staged (uncommitted) registrations are
45023
- * invisible here; only committed ones resolve. */
45025
+ * invisible here; only committed ones resolve. A key whose declared provider has not loaded throws
45026
+ * too, naming that: {@link load} resolves it. */
45024
45027
  resolve(kind, name) {
45025
45028
  const ext = this.#byKey.get(this.#canonical(kind, name));
45026
- if (!ext)
45029
+ if (!ext) {
45030
+ if (this.#providers.has(`${kind}:${name}`))
45031
+ throw new Error(`${kind} "${name}" is declared by a provider this process has not loaded`);
45027
45032
  throw new Error(`no ${kind} registered for "${name}"`);
45033
+ }
45028
45034
  return ext;
45029
45035
  }
45036
+ /** Declare a provider: a module that registers `provides` when it is imported. Nothing is imported
45037
+ * here. A key that another provider already declares is refused, so a key has one provider. */
45038
+ provide(provider) {
45039
+ const keys = provider.provides.map((ref) => `${ref.kind}:${ref.name}`);
45040
+ for (const key of keys)
45041
+ if (this.#providers.has(key))
45042
+ throw new Error(`extension provider already declared: ${key}`);
45043
+ const entry = { provider };
45044
+ for (const key of keys)
45045
+ this.#providers.set(key, entry);
45046
+ }
45047
+ /** Whether a provider was declared for exactly this kind + name, loaded or not. A boolean probe
45048
+ * that never throws and imports nothing. */
45049
+ provides(kind, name) {
45050
+ return this.#providers.has(`${kind}:${name}`);
45051
+ }
45052
+ /** Resolve kind + name, first importing the provider declared for it unless that import has run.
45053
+ * Concurrent calls share one import. A key no provider declares resolves as {@link resolve} does.
45054
+ * A provider that loads without registering the key it declared throws: the declaration is wrong,
45055
+ * and no other extension stands in for it. */
45056
+ async load(kind, name) {
45057
+ const entry = this.#providers.get(`${kind}:${name}`);
45058
+ if (entry) {
45059
+ entry.loading ??= entry.provider.load();
45060
+ await entry.loading;
45061
+ if (!this.#byKey.has(this.#canonical(kind, name)))
45062
+ throw new Error(`the provider declared for ${kind} "${name}" loaded without registering it`);
45063
+ }
45064
+ return this.resolve(kind, name);
45065
+ }
45030
45066
  all(kind) {
45031
45067
  const values = [...this.#byKey.values()];
45032
45068
  return kind === void 0 ? values : values.filter((e) => e.kind === kind);
@@ -63077,10 +63113,10 @@ function date4(params) {
63077
63113
  config(en_default());
63078
63114
 
63079
63115
  // ../connector-core/dist/docs-bundle.generated.js
63080
- var DOCS_VERSION = "0.108.1";
63116
+ var DOCS_VERSION = "0.109.0";
63081
63117
  function loadDocsBundle() {
63082
63118
  return {
63083
- "version": "0.108.1",
63119
+ "version": "0.109.0",
63084
63120
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
63085
63121
  "pages": [
63086
63122
  {
@@ -45082,6 +45082,8 @@ function claims(ext) {
45082
45082
  }
45083
45083
  var Registry = class {
45084
45084
  #byKey = /* @__PURE__ */ new Map();
45085
+ /** `kind:name` → the declared provider that registers it, and its import once one has started. */
45086
+ #providers = /* @__PURE__ */ new Map();
45085
45087
  /** `kind:alias` → the claiming extension's `kind:name` key, for committed extensions. */
45086
45088
  #aliases = /* @__PURE__ */ new Map();
45087
45089
  /** While a stage is active in the CURRENT async context, {@link register} writes there instead of
@@ -45168,13 +45170,47 @@ var Registry = class {
45168
45170
  return this.#aliases.get(key) ?? key;
45169
45171
  }
45170
45172
  /** Resolve one extension by kind + name or alias. Unknown throws. Staged (uncommitted) registrations are
45171
- * invisible here; only committed ones resolve. */
45173
+ * invisible here; only committed ones resolve. A key whose declared provider has not loaded throws
45174
+ * too, naming that: {@link load} resolves it. */
45172
45175
  resolve(kind, name) {
45173
45176
  const ext = this.#byKey.get(this.#canonical(kind, name));
45174
- if (!ext)
45177
+ if (!ext) {
45178
+ if (this.#providers.has(`${kind}:${name}`))
45179
+ throw new Error(`${kind} "${name}" is declared by a provider this process has not loaded`);
45175
45180
  throw new Error(`no ${kind} registered for "${name}"`);
45181
+ }
45176
45182
  return ext;
45177
45183
  }
45184
+ /** Declare a provider: a module that registers `provides` when it is imported. Nothing is imported
45185
+ * here. A key that another provider already declares is refused, so a key has one provider. */
45186
+ provide(provider) {
45187
+ const keys = provider.provides.map((ref) => `${ref.kind}:${ref.name}`);
45188
+ for (const key of keys)
45189
+ if (this.#providers.has(key))
45190
+ throw new Error(`extension provider already declared: ${key}`);
45191
+ const entry = { provider };
45192
+ for (const key of keys)
45193
+ this.#providers.set(key, entry);
45194
+ }
45195
+ /** Whether a provider was declared for exactly this kind + name, loaded or not. A boolean probe
45196
+ * that never throws and imports nothing. */
45197
+ provides(kind, name) {
45198
+ return this.#providers.has(`${kind}:${name}`);
45199
+ }
45200
+ /** Resolve kind + name, first importing the provider declared for it unless that import has run.
45201
+ * Concurrent calls share one import. A key no provider declares resolves as {@link resolve} does.
45202
+ * A provider that loads without registering the key it declared throws: the declaration is wrong,
45203
+ * and no other extension stands in for it. */
45204
+ async load(kind, name) {
45205
+ const entry = this.#providers.get(`${kind}:${name}`);
45206
+ if (entry) {
45207
+ entry.loading ??= entry.provider.load();
45208
+ await entry.loading;
45209
+ if (!this.#byKey.has(this.#canonical(kind, name)))
45210
+ throw new Error(`the provider declared for ${kind} "${name}" loaded without registering it`);
45211
+ }
45212
+ return this.resolve(kind, name);
45213
+ }
45178
45214
  all(kind) {
45179
45215
  const values = [...this.#byKey.values()];
45180
45216
  return kind === void 0 ? values : values.filter((e) => e.kind === kind);
@@ -65882,10 +65918,10 @@ function date4(params) {
65882
65918
  config(en_default());
65883
65919
 
65884
65920
  // ../connector-core/dist/docs-bundle.generated.js
65885
- var DOCS_VERSION = "0.108.1";
65921
+ var DOCS_VERSION = "0.109.0";
65886
65922
  function loadDocsBundle() {
65887
65923
  return {
65888
- "version": "0.108.1",
65924
+ "version": "0.109.0",
65889
65925
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
65890
65926
  "pages": [
65891
65927
  {
@@ -57541,6 +57541,8 @@ function claims(ext) {
57541
57541
  }
57542
57542
  var Registry = class {
57543
57543
  #byKey = /* @__PURE__ */ new Map();
57544
+ /** `kind:name` → the declared provider that registers it, and its import once one has started. */
57545
+ #providers = /* @__PURE__ */ new Map();
57544
57546
  /** `kind:alias` → the claiming extension's `kind:name` key, for committed extensions. */
57545
57547
  #aliases = /* @__PURE__ */ new Map();
57546
57548
  /** While a stage is active in the CURRENT async context, {@link register} writes there instead of
@@ -57627,13 +57629,47 @@ var Registry = class {
57627
57629
  return this.#aliases.get(key) ?? key;
57628
57630
  }
57629
57631
  /** Resolve one extension by kind + name or alias. Unknown throws. Staged (uncommitted) registrations are
57630
- * invisible here; only committed ones resolve. */
57632
+ * invisible here; only committed ones resolve. A key whose declared provider has not loaded throws
57633
+ * too, naming that: {@link load} resolves it. */
57631
57634
  resolve(kind, name) {
57632
57635
  const ext = this.#byKey.get(this.#canonical(kind, name));
57633
- if (!ext)
57636
+ if (!ext) {
57637
+ if (this.#providers.has(`${kind}:${name}`))
57638
+ throw new Error(`${kind} "${name}" is declared by a provider this process has not loaded`);
57634
57639
  throw new Error(`no ${kind} registered for "${name}"`);
57640
+ }
57635
57641
  return ext;
57636
57642
  }
57643
+ /** Declare a provider: a module that registers `provides` when it is imported. Nothing is imported
57644
+ * here. A key that another provider already declares is refused, so a key has one provider. */
57645
+ provide(provider) {
57646
+ const keys = provider.provides.map((ref) => `${ref.kind}:${ref.name}`);
57647
+ for (const key of keys)
57648
+ if (this.#providers.has(key))
57649
+ throw new Error(`extension provider already declared: ${key}`);
57650
+ const entry = { provider };
57651
+ for (const key of keys)
57652
+ this.#providers.set(key, entry);
57653
+ }
57654
+ /** Whether a provider was declared for exactly this kind + name, loaded or not. A boolean probe
57655
+ * that never throws and imports nothing. */
57656
+ provides(kind, name) {
57657
+ return this.#providers.has(`${kind}:${name}`);
57658
+ }
57659
+ /** Resolve kind + name, first importing the provider declared for it unless that import has run.
57660
+ * Concurrent calls share one import. A key no provider declares resolves as {@link resolve} does.
57661
+ * A provider that loads without registering the key it declared throws: the declaration is wrong,
57662
+ * and no other extension stands in for it. */
57663
+ async load(kind, name) {
57664
+ const entry = this.#providers.get(`${kind}:${name}`);
57665
+ if (entry) {
57666
+ entry.loading ??= entry.provider.load();
57667
+ await entry.loading;
57668
+ if (!this.#byKey.has(this.#canonical(kind, name)))
57669
+ throw new Error(`the provider declared for ${kind} "${name}" loaded without registering it`);
57670
+ }
57671
+ return this.resolve(kind, name);
57672
+ }
57637
57673
  all(kind) {
57638
57674
  const values = [...this.#byKey.values()];
57639
57675
  return kind === void 0 ? values : values.filter((e) => e.kind === kind);
@@ -58085,10 +58121,10 @@ async function submitFeedback(input, options = {}) {
58085
58121
  import { execFileSync } from "node:child_process";
58086
58122
 
58087
58123
  // ../connector-core/dist/docs-bundle.generated.js
58088
- var DOCS_VERSION = "0.108.1";
58124
+ var DOCS_VERSION = "0.109.0";
58089
58125
  function loadDocsBundle() {
58090
58126
  return {
58091
- "version": "0.108.1",
58127
+ "version": "0.109.0",
58092
58128
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
58093
58129
  "pages": [
58094
58130
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/connector-jcode",
3
3
  "description": "Cotal connector for Jcode: a host-mode mesh peer driven through Jcode's Harness API bridge.",
4
- "version": "0.108.1",
4
+ "version": "0.109.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -44981,6 +44981,8 @@ function claims(ext) {
44981
44981
  }
44982
44982
  var Registry = class {
44983
44983
  #byKey = /* @__PURE__ */ new Map();
44984
+ /** `kind:name` → the declared provider that registers it, and its import once one has started. */
44985
+ #providers = /* @__PURE__ */ new Map();
44984
44986
  /** `kind:alias` → the claiming extension's `kind:name` key, for committed extensions. */
44985
44987
  #aliases = /* @__PURE__ */ new Map();
44986
44988
  /** While a stage is active in the CURRENT async context, {@link register} writes there instead of
@@ -45067,13 +45069,47 @@ var Registry = class {
45067
45069
  return this.#aliases.get(key) ?? key;
45068
45070
  }
45069
45071
  /** Resolve one extension by kind + name or alias. Unknown throws. Staged (uncommitted) registrations are
45070
- * invisible here; only committed ones resolve. */
45072
+ * invisible here; only committed ones resolve. A key whose declared provider has not loaded throws
45073
+ * too, naming that: {@link load} resolves it. */
45071
45074
  resolve(kind, name) {
45072
45075
  const ext = this.#byKey.get(this.#canonical(kind, name));
45073
- if (!ext)
45076
+ if (!ext) {
45077
+ if (this.#providers.has(`${kind}:${name}`))
45078
+ throw new Error(`${kind} "${name}" is declared by a provider this process has not loaded`);
45074
45079
  throw new Error(`no ${kind} registered for "${name}"`);
45080
+ }
45075
45081
  return ext;
45076
45082
  }
45083
+ /** Declare a provider: a module that registers `provides` when it is imported. Nothing is imported
45084
+ * here. A key that another provider already declares is refused, so a key has one provider. */
45085
+ provide(provider) {
45086
+ const keys = provider.provides.map((ref) => `${ref.kind}:${ref.name}`);
45087
+ for (const key of keys)
45088
+ if (this.#providers.has(key))
45089
+ throw new Error(`extension provider already declared: ${key}`);
45090
+ const entry = { provider };
45091
+ for (const key of keys)
45092
+ this.#providers.set(key, entry);
45093
+ }
45094
+ /** Whether a provider was declared for exactly this kind + name, loaded or not. A boolean probe
45095
+ * that never throws and imports nothing. */
45096
+ provides(kind, name) {
45097
+ return this.#providers.has(`${kind}:${name}`);
45098
+ }
45099
+ /** Resolve kind + name, first importing the provider declared for it unless that import has run.
45100
+ * Concurrent calls share one import. A key no provider declares resolves as {@link resolve} does.
45101
+ * A provider that loads without registering the key it declared throws: the declaration is wrong,
45102
+ * and no other extension stands in for it. */
45103
+ async load(kind, name) {
45104
+ const entry = this.#providers.get(`${kind}:${name}`);
45105
+ if (entry) {
45106
+ entry.loading ??= entry.provider.load();
45107
+ await entry.loading;
45108
+ if (!this.#byKey.has(this.#canonical(kind, name)))
45109
+ throw new Error(`the provider declared for ${kind} "${name}" loaded without registering it`);
45110
+ }
45111
+ return this.resolve(kind, name);
45112
+ }
45077
45113
  all(kind) {
45078
45114
  const values = [...this.#byKey.values()];
45079
45115
  return kind === void 0 ? values : values.filter((e) => e.kind === kind);
@@ -65593,10 +65629,10 @@ function date4(params) {
65593
65629
  config(en_default());
65594
65630
 
65595
65631
  // ../connector-core/dist/docs-bundle.generated.js
65596
- var DOCS_VERSION = "0.108.1";
65632
+ var DOCS_VERSION = "0.109.0";
65597
65633
  function loadDocsBundle() {
65598
65634
  return {
65599
- "version": "0.108.1",
65635
+ "version": "0.109.0",
65600
65636
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
65601
65637
  "pages": [
65602
65638
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/connector-opencode",
3
3
  "description": "Cotal connector for OpenCode: a native in-process plugin that joins a session to the mesh.",
4
- "version": "0.108.1",
4
+ "version": "0.109.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -27449,10 +27449,10 @@ import { isConcreteChannel as isConcreteChannel3, channelInAllow as channelInAll
27449
27449
  import { parsePrincipalKey as parsePrincipalKey2, peerLabel as peerLabel3 } from "@cotal-ai/core";
27450
27450
 
27451
27451
  // ../connector-core/dist/docs-bundle.generated.js
27452
- var DOCS_VERSION = "0.108.1";
27452
+ var DOCS_VERSION = "0.109.0";
27453
27453
  function loadDocsBundle() {
27454
27454
  return {
27455
- "version": "0.108.1",
27455
+ "version": "0.109.0",
27456
27456
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
27457
27457
  "pages": [
27458
27458
  {
@@ -45114,6 +45114,8 @@ function claims(ext) {
45114
45114
  }
45115
45115
  var Registry = class {
45116
45116
  #byKey = /* @__PURE__ */ new Map();
45117
+ /** `kind:name` → the declared provider that registers it, and its import once one has started. */
45118
+ #providers = /* @__PURE__ */ new Map();
45117
45119
  /** `kind:alias` → the claiming extension's `kind:name` key, for committed extensions. */
45118
45120
  #aliases = /* @__PURE__ */ new Map();
45119
45121
  /** While a stage is active in the CURRENT async context, {@link register} writes there instead of
@@ -45200,13 +45202,47 @@ var Registry = class {
45200
45202
  return this.#aliases.get(key) ?? key;
45201
45203
  }
45202
45204
  /** Resolve one extension by kind + name or alias. Unknown throws. Staged (uncommitted) registrations are
45203
- * invisible here; only committed ones resolve. */
45205
+ * invisible here; only committed ones resolve. A key whose declared provider has not loaded throws
45206
+ * too, naming that: {@link load} resolves it. */
45204
45207
  resolve(kind, name) {
45205
45208
  const ext = this.#byKey.get(this.#canonical(kind, name));
45206
- if (!ext)
45209
+ if (!ext) {
45210
+ if (this.#providers.has(`${kind}:${name}`))
45211
+ throw new Error(`${kind} "${name}" is declared by a provider this process has not loaded`);
45207
45212
  throw new Error(`no ${kind} registered for "${name}"`);
45213
+ }
45208
45214
  return ext;
45209
45215
  }
45216
+ /** Declare a provider: a module that registers `provides` when it is imported. Nothing is imported
45217
+ * here. A key that another provider already declares is refused, so a key has one provider. */
45218
+ provide(provider) {
45219
+ const keys = provider.provides.map((ref) => `${ref.kind}:${ref.name}`);
45220
+ for (const key of keys)
45221
+ if (this.#providers.has(key))
45222
+ throw new Error(`extension provider already declared: ${key}`);
45223
+ const entry = { provider };
45224
+ for (const key of keys)
45225
+ this.#providers.set(key, entry);
45226
+ }
45227
+ /** Whether a provider was declared for exactly this kind + name, loaded or not. A boolean probe
45228
+ * that never throws and imports nothing. */
45229
+ provides(kind, name) {
45230
+ return this.#providers.has(`${kind}:${name}`);
45231
+ }
45232
+ /** Resolve kind + name, first importing the provider declared for it unless that import has run.
45233
+ * Concurrent calls share one import. A key no provider declares resolves as {@link resolve} does.
45234
+ * A provider that loads without registering the key it declared throws: the declaration is wrong,
45235
+ * and no other extension stands in for it. */
45236
+ async load(kind, name) {
45237
+ const entry = this.#providers.get(`${kind}:${name}`);
45238
+ if (entry) {
45239
+ entry.loading ??= entry.provider.load();
45240
+ await entry.loading;
45241
+ if (!this.#byKey.has(this.#canonical(kind, name)))
45242
+ throw new Error(`the provider declared for ${kind} "${name}" loaded without registering it`);
45243
+ }
45244
+ return this.resolve(kind, name);
45245
+ }
45210
45246
  all(kind) {
45211
45247
  const values = [...this.#byKey.values()];
45212
45248
  return kind === void 0 ? values : values.filter((e) => e.kind === kind);
@@ -65891,10 +65927,10 @@ function date4(params) {
65891
65927
  config(en_default());
65892
65928
 
65893
65929
  // ../connector-core/dist/docs-bundle.generated.js
65894
- var DOCS_VERSION = "0.108.1";
65930
+ var DOCS_VERSION = "0.109.0";
65895
65931
  function loadDocsBundle() {
65896
65932
  return {
65897
- "version": "0.108.1",
65933
+ "version": "0.109.0",
65898
65934
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
65899
65935
  "pages": [
65900
65936
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cotal-ai/pi",
3
- "version": "0.108.1",
3
+ "version": "0.109.0",
4
4
  "license": "Apache-2.0",
5
5
  "keywords": [
6
6
  "cotal",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/web",
3
3
  "description": "Cotal browser observability dashboard as an owned service preset.",
4
- "version": "0.108.1",
4
+ "version": "0.109.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",