@twinsearth/w2m-dsh-plugin 0.5.4 → 0.5.5
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 +62 -0
- package/cordis.patch.yml +27 -4
- package/lib/client.js +6 -4
- package/lib/index.js +16 -11
- package/lib/tools.js +9 -3
- package/package.json +1 -1
- package/src/plugin/fleet-target.mjs +84 -20
- package/src/plugin/tools.mjs +7 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,70 @@ All notable changes to this project are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.5.5] — 2026-10-11
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
* **The v0.5.4 loader failure, with the cause the loader actually reported** rather than the hypothesis
|
|
12
|
+
that stood in for it:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
w2m (@twinsearth/w2m-dsh-plugin/tools): Error: cannot get property "connection" without inject
|
|
16
|
+
at registerTargetRoutes (src/plugin/fleet-target.mjs:483:25)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
cordis throws on reading a service property the fiber never declared, so the entry died and took all
|
|
20
|
+
eight tools with it. **Every existing test was blind to this**, because they drive the plugin with a
|
|
21
|
+
plain-object context where an undeclared read merely yields `undefined` — the fake was more forgiving
|
|
22
|
+
than the runtime. Fixed with `ctx.inject(['connection'], …)`, which is also the only shape that can
|
|
23
|
+
work: in the real composition the service is genuinely absent while `apply()` runs, and siblings are
|
|
24
|
+
mounted concurrently.
|
|
25
|
+
* **The client half was never composed either, for a second and independent reason:** the bundle row
|
|
26
|
+
named the subpath `@twinsearth/w2m-dsh-plugin/tools` instead of the package, and a client package is
|
|
27
|
+
identified by its Loader row specifier — a subpath resolves to no `package.json`, so `dsh.client` was
|
|
28
|
+
never read and no boot-graph row was built. The row now names the package.
|
|
29
|
+
* **A silent route rejection:** the control fetched `/w2m/target`, but fetch routes are validated
|
|
30
|
+
against `/api/`, and the refusal failed only a child fiber, so nothing surfaced. Now
|
|
31
|
+
`/api/w2m/target`, mirrored in the shipped bundle.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
* **`test/loader-entry.test.mjs`** — the test that would have caught v0.5.4: it packs the tree, installs
|
|
36
|
+
the tarball with the installation's own `dsh plugin add` into a throwaway profile under a throwaway
|
|
37
|
+
`DSH_HOME`, and boots it with the real `runProfile` under the Harness runtime, asserting that the
|
|
38
|
+
entry activates, all eight tools are registered, the boot-graph row is composed from the shipped
|
|
39
|
+
bundle, and no failed entry names the package. **Proved in both directions**: 6/6 pass on the fixed
|
|
40
|
+
tree and 6/6 fail against the preserved v0.5.4 tarball, failing on precisely the loader error quoted
|
|
41
|
+
above. It skips loudly, naming the probes it tried, when no installation is found.
|
|
42
|
+
* Cheap always-on guards in `test/client-bundle.test.mjs` that need no Harness: the platform field, the
|
|
43
|
+
client export, the row must be the bare package name, and the bundle's route must equal the host's.
|
|
44
|
+
|
|
45
|
+
### Notes
|
|
46
|
+
|
|
47
|
+
* **An upgrade from v0.5.4 requires one edit outside this package:** `cordis.patch.yml` in the profile
|
|
48
|
+
must name the package (`@twinsearth/w2m-dsh-plugin`), not the `/tools` subpath. With the corrected
|
|
49
|
+
bundle row, a mismatch makes the loader skip the whole patch — silently reverting `rabbitUrl`,
|
|
50
|
+
`operatorToken`, `stateDir`, `projectDir`, `machineName`, `p2pMode` and `allowedCommands` to their
|
|
51
|
+
shipped defaults. Measured both ways with `--dump-config`.
|
|
52
|
+
* **0.5.4 remains DO NOT INSTALL.** This release exists so that a rebuilt artifact is distinguishable
|
|
53
|
+
from the broken one by version alone.
|
|
54
|
+
* Still unverified, and not claimed: how the control *renders*. No browser was opened. What is proven is
|
|
55
|
+
the entire host side — the entry activates, the eight tools register, the boot-graph row is composed
|
|
56
|
+
from the shipped bundle, the route is registered and attached — plus the seat shape in a VM test.
|
|
7
57
|
## [0.5.4] — 2026-10-11
|
|
8
58
|
|
|
59
|
+
> **DO NOT INSTALL 0.5.4.** It fails to load in the Harness: the loader entry
|
|
60
|
+
> include:@twinsearth/w2m-dsh-plugin/tools reports iberPhase: failed, so **all eight tools
|
|
61
|
+
> disappear** and the client half never registers. The package verifies in isolation
|
|
62
|
+
> (scripts/verify-installed.mjs reports 8 tools registered) and its exports map is complete, so the
|
|
63
|
+
> failure is in the real loader path -- the newly declared dsh.client half being composed there, with
|
|
64
|
+
> lib/client.js being browser code that has no window under a host-side load. That cause is a
|
|
65
|
+
> hypothesis, not a measurement; the loader's own error is still to be read. 0.5.5 fixes it and adds the
|
|
66
|
+
> test that should have caught it: **load the packed artifact through the real loader path**, which is
|
|
67
|
+
> the step this release skipped. The tag and the npm version stay as published history; they are simply
|
|
68
|
+
> not installable.
|
|
69
|
+
|
|
70
|
+
|
|
9
71
|
### Added
|
|
10
72
|
|
|
11
73
|
* **A dispatch-target control inside the chat composer.** A client half registers into
|
package/cordis.patch.yml
CHANGED
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
# This file is the bundle patch declared by package.json's `dsh.bundle.patch`.
|
|
2
|
-
# It mounts the plugin
|
|
3
|
-
#
|
|
4
|
-
#
|
|
2
|
+
# It mounts the plugin by its package name, whose root export is the plugin
|
|
3
|
+
# (`lib/index.js` re-exports `./tools.js`), so reading this file tells you which
|
|
4
|
+
# package becomes the plugin.
|
|
5
|
+
#
|
|
6
|
+
# ---------------------------------------------------------------------------
|
|
7
|
+
# Why the row names the package and not the `/tools` subpath (v0.5.4)
|
|
8
|
+
# ---------------------------------------------------------------------------
|
|
9
|
+
# Until v0.5.4 this row said `name: '@twinsearth/w2m-dsh-plugin/tools'`, and for a
|
|
10
|
+
# host-only plugin that was fine. It stops being fine the moment the package also
|
|
11
|
+
# ships a browser half, because the client module system identifies a package by
|
|
12
|
+
# the *package specifier* its Loader row carries:
|
|
13
|
+
#
|
|
14
|
+
# client-modules: resolveMeta(loaderName, baseUrl) (dsh-client-modules)
|
|
15
|
+
# exactPackageSpecifier('@twinsearth/w2m-dsh-plugin/tools') -> undefined
|
|
16
|
+
# ... -> locatePkgJson returns undefined -> the entry is not a client package
|
|
17
|
+
#
|
|
18
|
+
# A subpath specifier resolves to no package manifest at all, so a `/tools` row is
|
|
19
|
+
# invisible to the scan: `lib/client.js` is never composed into `__DSH_BOOT__`, and
|
|
20
|
+
# the composer control can never register -- whatever else is fixed. Measured on the
|
|
21
|
+
# 0.5.4 tarball through the real Loader: the composed boot graph held rows for
|
|
22
|
+
# `@deepseek-ai/dsh-typert-registry` and `@deepseek-ai/dsh-api-gateway` and none for
|
|
23
|
+
# this package. Naming the bare package fixes it, because the root export already
|
|
24
|
+
# re-exports exactly what `/tools` exports (`test/tools.test.mjs` asserts the two
|
|
25
|
+
# carry the same `inject`), so the host half is unchanged. `./tools` remains a
|
|
26
|
+
# supported mount point for anyone who wants it -- it is simply not the one this
|
|
27
|
+
# bundle uses.
|
|
5
28
|
#
|
|
6
29
|
# ---------------------------------------------------------------------------
|
|
7
30
|
# Why this is an `insert:` list and not a bare `- id: w2m`
|
|
@@ -83,7 +106,7 @@
|
|
|
83
106
|
# is visible rather than assumed.
|
|
84
107
|
- insert:
|
|
85
108
|
- id: w2m
|
|
86
|
-
name: '@twinsearth/w2m-dsh-plugin
|
|
109
|
+
name: '@twinsearth/w2m-dsh-plugin'
|
|
87
110
|
config:
|
|
88
111
|
rabbitUrl: ''
|
|
89
112
|
operatorToken: ''
|
package/lib/client.js
CHANGED
|
@@ -52,10 +52,12 @@ window.__ModuleLoader__.load({
|
|
|
52
52
|
// Wire
|
|
53
53
|
// -------------------------------------------------------------------------------------------
|
|
54
54
|
//
|
|
55
|
-
// Mirrors TARGET_ROUTE_PATH in src/plugin/fleet-target.mjs
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
|
|
55
|
+
// Mirrors TARGET_ROUTE_PATH in src/plugin/fleet-target.mjs, `/api` prefix included: the host's
|
|
56
|
+
// Connection service mounts its exact-fetch-route registry under that channel and refuses any
|
|
57
|
+
// path that does not start with `/api/`. Plain same-origin `fetch` rather than a Remote method:
|
|
58
|
+
// the route is mounted inside the host's authentication fence, so the page's own cookie is the
|
|
59
|
+
// credential and there is no descriptor to keep in sync.
|
|
60
|
+
const ROUTE = '/api/w2m/target';
|
|
59
61
|
|
|
60
62
|
/**
|
|
61
63
|
* The locale namespace and its two dictionaries.
|
package/lib/index.js
CHANGED
|
@@ -3,22 +3,27 @@
|
|
|
3
3
|
*
|
|
4
4
|
* TWO READERS, ONE EXPORT LIST
|
|
5
5
|
*
|
|
6
|
-
* `cordis.patch.yml`
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* `cordis.patch.yml` mounts this file: the profile reads the patch, sees
|
|
7
|
+
* `@twinsearth/w2m-dsh-plugin`, and loads `./index.js`. It names the *package* rather than the
|
|
8
|
+
* `tools` subpath on purpose, and the reason is measured rather than stylistic: the client module
|
|
9
|
+
* system (`@deepseek-ai/dsh-client-modules`) identifies a client package by the specifier its Loader
|
|
10
|
+
* row carries (`exactPackageSpecifier`), so a row naming `…/tools` resolves to no package.json at all
|
|
11
|
+
* — `dsh.client` is never read and the browser half is never composed into `__DSH_BOOT__`. The host
|
|
12
|
+
* would keep working and the composer control would silently never arrive; that is what v0.5.4
|
|
13
|
+
* shipped, and `test/loader-entry.test.mjs` now catches it through the real Loader.
|
|
9
14
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* module", and
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
15
|
+
* `./tools.js` remains a supported mount point for anyone who wants it, and it is still what the
|
|
16
|
+
* DSH plugin listing requirements look at: the checklist asks for a package that "exports an
|
|
17
|
+
* `apply(ctx)` module", and this root is that module. It used to be documentation only, so importing
|
|
18
|
+
* the package root yielded **no exports at all** (`Object.keys() === []`): a plugin that works
|
|
19
|
+
* perfectly when mounted by its patch and looks like an empty package to every tool that inspects it.
|
|
20
|
+
* That is a bad trade for one re-export line.
|
|
16
21
|
*
|
|
17
22
|
* WHY NOT MOVE THE PLUGIN HERE
|
|
18
23
|
*
|
|
19
24
|
* Re-exporting is not relocating: `./tools.js` stays the single definition, so there is still
|
|
20
25
|
* exactly one implementation of the plugin surface to keep in sync. Mounting *both* this entry and
|
|
21
|
-
* the subpath would register the eight tools twice, which is why the patch
|
|
22
|
-
*
|
|
26
|
+
* the subpath would register the eight tools twice, which is why the patch mounts exactly one of
|
|
27
|
+
* them.
|
|
23
28
|
*/
|
|
24
29
|
export { apply, inject, resetDefineToolCacheForTests } from './tools.js';
|
package/lib/tools.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Package-facing plugin entry: `@twinsearth/w2m-dsh-plugin/tools`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The documented subpath entry point, and the seam between the published package
|
|
5
|
+
* layout (`lib/`, what npm ships as the documented entry) and the implementation
|
|
6
|
+
* (`src/`, where the code is actually readable).
|
|
7
|
+
*
|
|
8
|
+
* `cordis.patch.yml` mounts the package *root* (`lib/index.js`), which re-exports
|
|
9
|
+
* this file, because the client module system only recognises a package whose
|
|
10
|
+
* Loader row carries the bare package specifier. Both paths land on the same
|
|
11
|
+
* `apply` and `inject` -- `test/tools.test.mjs` asserts that -- so this remains a
|
|
12
|
+
* supported mount point for a profile that prefers it.
|
|
7
13
|
*
|
|
8
14
|
* Nothing is re-implemented here on purpose: a second definition of the plugin
|
|
9
15
|
* surface would be a second thing to keep in sync.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinsearth/w2m-dsh-plugin",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "DSH: Windows2MacOS — drive the same project on online Windows and macOS machines from one DeepSeek account, across networks and regions. P2P hole punching is the default path (relay + shared server as rendezvous, ledger and fallback), with a bundled STUN responder, Tailscale/public-VPS/tunnel shapes, Rabbit relay + per-machine Localside + eight DSH tools (replicate / split), nine aggregate verdicts and signed requests.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -27,10 +27,12 @@
|
|
|
27
27
|
*
|
|
28
28
|
* # The wire, and why it is this small
|
|
29
29
|
*
|
|
30
|
-
* Two exact Fetch routes on the host's `/api` carrier, mounted inside its authentication fence
|
|
30
|
+
* Two exact Fetch routes on the host's `/api` carrier, mounted inside its authentication fence.
|
|
31
|
+
* The `/api` prefix is the registry's own channel — see {@link TARGET_ROUTE_PATH} — so these are the
|
|
32
|
+
* paths as the host registers them, and the page fetches the same path document-relative:
|
|
31
33
|
*
|
|
32
|
-
* GET /w2m/target?session_id=… the fleet and this session's selection, as one snapshot
|
|
33
|
-
* POST /w2m/target { session_id, machine_id|null } → the same snapshot
|
|
34
|
+
* GET /api/w2m/target?session_id=… the fleet and this session's selection, as one snapshot
|
|
35
|
+
* POST /api/w2m/target { session_id, machine_id|null } → the same snapshot
|
|
34
36
|
*
|
|
35
37
|
* Plain `Response.json`, no Typert descriptor: this package is dependency-free, and a generated
|
|
36
38
|
* strict Remote contribution is neither reachable from plain JavaScript nor worth a codec for one
|
|
@@ -48,8 +50,19 @@
|
|
|
48
50
|
* get.
|
|
49
51
|
*/
|
|
50
52
|
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Both routes hang off this exact path; the browser half reads the same constant.
|
|
55
|
+
*
|
|
56
|
+
* The `/api` prefix is not decoration and not ours: `@deepseek-ai/dsh-client-connection` mounts the
|
|
57
|
+
* whole fetch-route registry under its `/api` channel and validates every registration with
|
|
58
|
+
* `endpointFromPath('/api', path)`, which returns undefined for anything that does not start with
|
|
59
|
+
* `/api/`. A `/w2m/target` registration is therefore refused — `connection: invalid exact Fetch route
|
|
60
|
+
* "/w2m/target"` — inside the injected callback, where it failed the *child* fiber and left the host
|
|
61
|
+
* entry looking perfectly healthy. The shipped browser halves all follow the same rule
|
|
62
|
+
* (`dsh-client-file-upload` uses `/api/session/uploadFileBinary`), and the page fetches the same
|
|
63
|
+
* document-relative path.
|
|
64
|
+
*/
|
|
65
|
+
export const TARGET_ROUTE_PATH = '/api/w2m/target';
|
|
53
66
|
|
|
54
67
|
/**
|
|
55
68
|
* The store bucket used when a dispatch carries no session.
|
|
@@ -460,16 +473,40 @@ export function createLocalIdentity(read) {
|
|
|
460
473
|
};
|
|
461
474
|
}
|
|
462
475
|
|
|
476
|
+
/** The one diagnostic for "this host cannot carry the composer control", shared by both causes. */
|
|
477
|
+
const NO_ROUTE_REGISTRY =
|
|
478
|
+
'this host provides no `connection.fetch` route registry, so the composer control cannot reach the plugin';
|
|
479
|
+
|
|
463
480
|
/**
|
|
464
481
|
* Mount the two browser routes, if this host has a fetch-route registry to mount them on.
|
|
465
482
|
*
|
|
466
483
|
* Returning a status object instead of throwing keeps the one interesting case loud *and*
|
|
467
484
|
* survivable: a host built without `@deepseek-ai/dsh-client-connection` still gets a working plugin
|
|
468
|
-
* with
|
|
469
|
-
* load because a UI nicety has nowhere to attach.
|
|
470
|
-
*
|
|
471
|
-
*
|
|
472
|
-
*
|
|
485
|
+
* with all eight tools and no composer control, which is strictly better than a plugin that refuses
|
|
486
|
+
* to load because a UI nicety has nowhere to attach.
|
|
487
|
+
*
|
|
488
|
+
* # Why the service is declared with `ctx.inject`, and never read as `ctx.connection`
|
|
489
|
+
*
|
|
490
|
+
* Cordis resolves services per fiber: a property read of a name this plugin did not declare in its
|
|
491
|
+
* `inject` list **throws** — `cannot get property "connection" without inject` — and it throws
|
|
492
|
+
* whether or not some other plugin provides that service. `ctx.inject(names, callback)` is the
|
|
493
|
+
* declaration that makes the read legal, and it is the *optional* form: the plugin's own list stays
|
|
494
|
+
* `['tools']`, so a host with no Connection service still activates and still registers all eight
|
|
495
|
+
* tools — the callback below simply never runs. v0.5.4 shipped the plain property read, and the whole
|
|
496
|
+
* entry then failed on a web host and on a base-only host alike, because the throw does not depend on
|
|
497
|
+
* the service existing.
|
|
498
|
+
*
|
|
499
|
+
* `ctx.inject` also drops the ordering assumption a one-shot read would carry: the Loader creates
|
|
500
|
+
* sibling entries concurrently (`EntryGroup.update` → `Promise.all`), so a host that *does* provide
|
|
501
|
+
* Connection may still be activating it while this plugin's `apply` runs. A synchronous read would
|
|
502
|
+
* report "no registry" for a control that was about to become attachable.
|
|
503
|
+
*
|
|
504
|
+
* The status object is mutated in place when the callback runs, so `w2m_status` — called long after
|
|
505
|
+
* activation — reads what happened rather than what was knowable at `apply` time.
|
|
506
|
+
*
|
|
507
|
+
* @param {object|null|undefined} ctx Cordis context; `ctx.inject(['connection'], …)` is how the
|
|
508
|
+
* optional service is declared and read. A context without `inject` gets no route and no warning,
|
|
509
|
+
* which is the same status as a host that has no Connection at all.
|
|
473
510
|
* @param {object} deps
|
|
474
511
|
* @param {() => object} deps.cfg Current merged plugin config.
|
|
475
512
|
* @param {object} deps.store The selection store.
|
|
@@ -480,17 +517,43 @@ export function createLocalIdentity(read) {
|
|
|
480
517
|
* when the host has a Connection service that lacks the registry — the one case worth a warning.
|
|
481
518
|
*/
|
|
482
519
|
export function registerTargetRoutes(ctx, deps) {
|
|
483
|
-
const
|
|
520
|
+
const status = {
|
|
521
|
+
mounted: false,
|
|
522
|
+
unexpected: false,
|
|
523
|
+
reason: NO_ROUTE_REGISTRY,
|
|
524
|
+
};
|
|
525
|
+
if (typeof ctx?.inject === 'function') {
|
|
526
|
+
ctx.inject(['connection'], (webCtx) => {
|
|
527
|
+
mountTargetRoutes(webCtx.connection, deps, status, ctx.logger);
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
return status;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Attach the route pair to one host's fetch registry, recording the outcome on `status`.
|
|
535
|
+
*
|
|
536
|
+
* The registration is owned by the context it is made through — `register` is a Connection method
|
|
537
|
+
* bound to the calling fiber, so it is released with the injected child fiber — which is why there
|
|
538
|
+
* is no `ctx.effect` wrapper here.
|
|
539
|
+
*
|
|
540
|
+
* @param {object|null|undefined} connection The `connection` service, when the host has one.
|
|
541
|
+
* @param {object} deps
|
|
542
|
+
* @param {{mounted: boolean, unexpected: boolean, reason: string|null}} status Mutated in place.
|
|
543
|
+
* @param {object} [logger] The plugin's logger, for the one mismatch worth a line.
|
|
544
|
+
* @returns {void}
|
|
545
|
+
*/
|
|
546
|
+
function mountTargetRoutes(connection, deps, status, logger) {
|
|
484
547
|
const registry = connection?.fetch;
|
|
485
548
|
if (registry === undefined || typeof registry.register !== 'function') {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
549
|
+
// The distinction matters to the log: a host with **no** Connection at all is simply not a web
|
|
550
|
+
// composition, and warning about it would be noise on every headless run. A host that has
|
|
551
|
+
// Connection but no fetch registry is a real mismatch worth one line.
|
|
552
|
+
status.unexpected = connection !== null && connection !== undefined;
|
|
553
|
+
if (status.unexpected) {
|
|
554
|
+
logger?.warn?.(`w2m: the composer target control is inactive — ${NO_ROUTE_REGISTRY}`);
|
|
555
|
+
}
|
|
556
|
+
return;
|
|
494
557
|
}
|
|
495
558
|
|
|
496
559
|
let cache = { at: 0, value: null };
|
|
@@ -599,5 +662,6 @@ export function registerTargetRoutes(ctx, deps) {
|
|
|
599
662
|
},
|
|
600
663
|
});
|
|
601
664
|
|
|
602
|
-
|
|
665
|
+
status.mounted = true;
|
|
666
|
+
status.reason = null;
|
|
603
667
|
}
|
package/src/plugin/tools.mjs
CHANGED
|
@@ -131,7 +131,7 @@ const MAX_STAGES = 16;
|
|
|
131
131
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
132
132
|
* overrides it at runtime for tests and packagers.
|
|
133
133
|
*/
|
|
134
|
-
const PLUGIN_VERSION = '0.5.
|
|
134
|
+
const PLUGIN_VERSION = '0.5.5';
|
|
135
135
|
|
|
136
136
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
137
137
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|
|
@@ -2872,6 +2872,12 @@ export async function apply(ctx, config = {}) {
|
|
|
2872
2872
|
// host without `connection.fetch` still gets every tool, and `w2m_status` reports the absence —
|
|
2873
2873
|
// which is the honest place for it, since a host that has no Connection at all is simply not a web
|
|
2874
2874
|
// composition and does not need a warning on every headless run.
|
|
2875
|
+
//
|
|
2876
|
+
// Nothing here reads the service: `registerTargetRoutes` declares the optional dependency with
|
|
2877
|
+
// `ctx.inject` and attaches from that callback (the comment there records why a plain
|
|
2878
|
+
// `ctx.connection` read fails the whole entry, and why the read cannot be synchronous anyway). The
|
|
2879
|
+
// one mismatch worth a log line — a Connection that carries no fetch registry — is logged where it
|
|
2880
|
+
// is observed, inside that callback, so this call returns a status object that stays live.
|
|
2875
2881
|
const targetRoutes = registerTargetRoutes(ctx, {
|
|
2876
2882
|
cfg: () => cfg,
|
|
2877
2883
|
store: defaultSelectionStore,
|
|
@@ -2879,9 +2885,6 @@ export async function apply(ctx, config = {}) {
|
|
|
2879
2885
|
request,
|
|
2880
2886
|
resolveToken,
|
|
2881
2887
|
});
|
|
2882
|
-
if (targetRoutes.unexpected) {
|
|
2883
|
-
ctx.logger?.warn?.(`w2m: the composer target control is inactive — ${targetRoutes.reason}`);
|
|
2884
|
-
}
|
|
2885
2888
|
|
|
2886
2889
|
/** Text output: rendered as JSON, because every one of these tools answers with a structure. */
|
|
2887
2890
|
const jsonOutput = {
|