blogwright 0.3.2 → 0.4.0-beta.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/README.md +11 -11
- package/agent/agent-manifest.json +1 -1
- package/agent/server.js +37 -19
- package/dist/adapters/fetch-ping.d.ts +1 -1
- package/dist/adapters/fetch-ping.js +3 -4
- package/dist/adapters/node-module-loader.d.ts +11 -0
- package/dist/adapters/node-module-loader.js +146 -0
- package/dist/adapters/process-package-manager.d.ts +41 -0
- package/dist/adapters/process-package-manager.js +116 -0
- package/dist/adapters/process-vcs.d.ts +5 -4
- package/dist/adapters/process-vcs.js +6 -6
- package/dist/agent-package.d.ts +1 -1
- package/dist/agent-package.js +4 -4
- package/dist/bin.js +13 -3
- package/dist/cli.d.ts +68 -1
- package/dist/cli.js +270 -89
- package/dist/commands.d.ts +70 -3
- package/dist/commands.js +180 -32
- package/dist/config-block.d.ts +34 -0
- package/dist/config-block.js +262 -0
- package/dist/context.d.ts +76 -6
- package/dist/context.js +98 -19
- package/dist/deploy.d.ts +2 -2
- package/dist/deploy.js +14 -14
- package/dist/graph.d.ts +27 -16
- package/dist/graph.js +1 -2
- package/dist/init.d.ts +37 -3
- package/dist/init.js +146 -23
- package/dist/known-commands.d.ts +63 -0
- package/dist/known-commands.js +78 -0
- package/dist/logger.js +0 -1
- package/dist/microvms.d.ts +2 -2
- package/dist/microvms.js +3 -4
- package/dist/nodes.d.ts +5 -3
- package/dist/nodes.js +97 -31
- package/dist/plugin-commands.d.ts +298 -0
- package/dist/plugin-commands.js +990 -0
- package/dist/plugins.d.ts +194 -0
- package/dist/plugins.js +523 -0
- package/dist/ports.d.ts +89 -1
- package/dist/ports.js +0 -1
- package/dist/render.d.ts +55 -0
- package/dist/render.js +89 -2
- package/dist/repo.d.ts +3 -3
- package/dist/repo.js +8 -9
- package/dist/rkey.js +0 -1
- package/dist/seo.d.ts +1 -1
- package/dist/seo.js +1 -2
- package/package.json +6 -6
- package/dist/adapters/fetch-ping.js.map +0 -1
- package/dist/adapters/process-vcs.js.map +0 -1
- package/dist/agent-package.js.map +0 -1
- package/dist/bin.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands.js.map +0 -1
- package/dist/context.js.map +0 -1
- package/dist/deploy.js.map +0 -1
- package/dist/graph.js.map +0 -1
- package/dist/init.js.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/microvms.js.map +0 -1
- package/dist/nodes.js.map +0 -1
- package/dist/ports.js.map +0 -1
- package/dist/render.js.map +0 -1
- package/dist/repo.js.map +0 -1
- package/dist/rkey.js.map +0 -1
- package/dist/seo.js.map +0 -1
- package/dist/test-support.d.ts +0 -45
- package/dist/test-support.js +0 -126
- package/dist/test-support.js.map +0 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin discovery: finds every installed `blogwright-*` package that
|
|
3
|
+
* declares a `blogwright.plugin` manifest field, loads it, and validates its
|
|
4
|
+
* default export against core's `Plugin` contract.
|
|
5
|
+
*
|
|
6
|
+
* The candidate set is the UNION of two sources, each resolved from its own
|
|
7
|
+
* directory - see `collectCandidates` below - because a consuming repo
|
|
8
|
+
* depends on `blogwright`, not on `blogwright-pds`: scanning the consumer's
|
|
9
|
+
* own `package.json` alone would never find a plugin bundled inside the CLI
|
|
10
|
+
* itself.
|
|
11
|
+
*
|
|
12
|
+
* Collect, never throw, for anything candidate-specific: a broken plugin -
|
|
13
|
+
* one that fails to resolve, whose manifest is malformed, or whose default
|
|
14
|
+
* export fails validation - becomes an entry in `failures`, not a thrown
|
|
15
|
+
* error that aborts the whole discovery pass. One bad dependency must not
|
|
16
|
+
* make `blogwright deploy` (or any other built-in command) unusable. The
|
|
17
|
+
* only things this module *does* throw for are the two preconditions
|
|
18
|
+
* discovery cannot proceed without at all: the repo's own `package.json` and
|
|
19
|
+
* the CLI's own `package.json`, both read before any candidate is resolved.
|
|
20
|
+
*
|
|
21
|
+
* The same collect-never-throw rule governs the two namespace-collision
|
|
22
|
+
* checks this module applies itself, after a candidate has already loaded
|
|
23
|
+
* and validated cleanly: a plugin whose declared name is one the CLI
|
|
24
|
+
* dispatches itself (`RESERVED_COMMANDS`, `known-commands.ts` - a leaf
|
|
25
|
+
* module with no imports of its own, so this domain module never has to
|
|
26
|
+
* import the composition root just to read it), and two plugins that
|
|
27
|
+
* declare the same name as each other. §CLI → Namespace collisions calls
|
|
28
|
+
* this "rejected with an error", but - exactly like a malformed manifest or
|
|
29
|
+
* a failed `validatePlugin` check above - that rejection is a reported
|
|
30
|
+
* `failures` entry, not a thrown one. Throwing here would let a single
|
|
31
|
+
* colliding plugin abort discovery for every other, unrelated plugin and
|
|
32
|
+
* every built-in command that runs it; `blogwright plugin list` (task 17)
|
|
33
|
+
* depends on the collect outcome too, since it is the one place a collision
|
|
34
|
+
* becomes visible to a human.
|
|
35
|
+
*
|
|
36
|
+
* `pds` is deliberately absent from `RESERVED_COMMANDS`, and adding it would
|
|
37
|
+
* now BREAK the namespace rather than merely shadow it. Task 29 deleted
|
|
38
|
+
* `cli.ts`'s hardcoded `command === 'pds'` branch: there is no built-in
|
|
39
|
+
* `pds` command left for a reservation to protect, and `blogwright pds
|
|
40
|
+
* <action>` is answered by the bundled `blogwright-pds` package, which
|
|
41
|
+
* declares the plugin name `pds` and is discovered here like any other
|
|
42
|
+
* plugin. Reserving the name would therefore aim
|
|
43
|
+
* `resolveNamespaceCollisions` below at that bundled plugin itself: it would
|
|
44
|
+
* become a `failures` entry rather than an installed one, and the namespace
|
|
45
|
+
* would stop working outright - `blogwright pds sync` exiting 1 with `no
|
|
46
|
+
* built-in command or installed plugin claims "pds"`, `blogwright --help`
|
|
47
|
+
* listing none of its six actions, and `blogwright plugin list` reporting it
|
|
48
|
+
* as reserved for a built-in command that no longer exists. Verified by
|
|
49
|
+
* adding `'pds'` to the set: discovery rejects the real bundled package and
|
|
50
|
+
* this file's real-disk integration cases fail on exactly that reason
|
|
51
|
+
* string. So the name stays unreserved on purpose, pinned by a test below.
|
|
52
|
+
*
|
|
53
|
+
* DECISION (task 13, record here for task 16 to find): a plugin's declared
|
|
54
|
+
* ACTIONS can collide with a generic action the CLI contributes, distinct
|
|
55
|
+
* from the namespace collisions above. §CLI → `blogwright <plugin> init`
|
|
56
|
+
* names exactly one such collision a boundary check can reject: a plugin
|
|
57
|
+
* declaring BOTH an `init` command in its own `commands` AND an `init?(io)`
|
|
58
|
+
* contributor is unsatisfiable, because a declared command always wins
|
|
59
|
+
* dispatch (`plugin-commands.ts`'s `matchAction` matches a plugin's own
|
|
60
|
+
* `commands` before the generic action is ever considered), so the
|
|
61
|
+
* contributor would ask its questions nowhere. That check - `rejectDeclaredInitCollisions`
|
|
62
|
+
* below - lives HERE, in this module's collision pass, rather than in core's
|
|
63
|
+
* `validatePlugin` (`blogwright-core`'s `plugin.ts`), for the same reason the
|
|
64
|
+
* namespace checks do: it is about actions the *CLI* contributes generically
|
|
65
|
+
* (the config-writing `init`), which core must not know exists, and this
|
|
66
|
+
* module already reports a plugin-level rejection as a `failures` entry
|
|
67
|
+
* rather than a thrown error. §CLI → Plugin lifecycle adds the sibling rule
|
|
68
|
+
* for `bootstrap`/`destroy` (always generic; a plugin may never declare
|
|
69
|
+
* either, full stop - no "unless paired with a contributor" nuance, since
|
|
70
|
+
* there is no bootstrap/destroy contributor to pair with). Task 16 adds
|
|
71
|
+
* `rejectDeclaredLifecycleCollisions` below, a sibling function called from
|
|
72
|
+
* the same place in `discover`, with that rule, so every declared-action
|
|
73
|
+
* collision rejection greps to this one module instead of splitting across
|
|
74
|
+
* whichever of the two tasks happened to land first. `status` is deliberately
|
|
75
|
+
* NOT part of that rule: a plugin may declare its own `status` command
|
|
76
|
+
* freely - `read()` lives on the plugin's own nodes, so no engine call is
|
|
77
|
+
* required the way `bootstrap`/`destroy` need one - and `plugin-commands.ts`'s
|
|
78
|
+
* ordinary `matchAction` precedence (a plugin's own commands win before any
|
|
79
|
+
* generic fallback is even considered) already gives a declared `status`
|
|
80
|
+
* command priority with no boundary check needed here.
|
|
81
|
+
*
|
|
82
|
+
* DECISION (task 19, recorded here plainly because task 28 has to reason
|
|
83
|
+
* about it when pds's config validation moves out of core): a plugin's own
|
|
84
|
+
* config block is validated for the ONE plugin being DISPATCHED, in the
|
|
85
|
+
* dispatch path (`runPlugin` calls {@link resolvePluginConfig} below), and
|
|
86
|
+
* never for every discovered plugin. Two reasons, and neither is taste:
|
|
87
|
+
*
|
|
88
|
+
* - `createContext` (`context.ts`) is the path every built-in command
|
|
89
|
+
* takes and it accepts no plugin list, so validating there would have to
|
|
90
|
+
* run `discover` on `deploy`, `status` and `bootstrap` - breaking the
|
|
91
|
+
* laziness rule (§CLI -> Plugin discovery: a built-in command loads no
|
|
92
|
+
* plugin module) that task 10's own test pins. There is no seam in
|
|
93
|
+
* `createContext` through which the dispatched plugin ALONE could be
|
|
94
|
+
* reached, because at that point no plugin has been chosen yet.
|
|
95
|
+
* - Validating every discovered plugin, wherever it happened, would let an
|
|
96
|
+
* unrelated plugin's malformed block abort a command that has nothing to
|
|
97
|
+
* do with it. A block for a plugin that is not installed is already
|
|
98
|
+
* valid and inert - the same contract `pds` has today - and a block for
|
|
99
|
+
* an installed plugin that is not the one being run is inert for exactly
|
|
100
|
+
* the same reason: nothing reads it.
|
|
101
|
+
*
|
|
102
|
+
* The corollary is that `blogwright <plugin> <action>` is the only thing
|
|
103
|
+
* that reports a bad block, and it reports only its own plugin's.
|
|
104
|
+
*/
|
|
105
|
+
import { type Plugin } from 'blogwright-core';
|
|
106
|
+
import type { Ports } from './ports.js';
|
|
107
|
+
/** Why one candidate package failed to become a usable plugin. */
|
|
108
|
+
interface PluginLoadFailure {
|
|
109
|
+
readonly packageName: string;
|
|
110
|
+
readonly reason: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* A successfully loaded, `validatePlugin`-passing plugin together with the
|
|
114
|
+
* package it came from - the provenance `blogwright plugin list` (task 17)
|
|
115
|
+
* reports, and nothing else needs.
|
|
116
|
+
*
|
|
117
|
+
* `packageJsonPath` is the path `ModuleLoader.packageJsonPathFor` resolved,
|
|
118
|
+
* NOT one derived from `ModuleLoader.resolve`'s entry file: a package
|
|
119
|
+
* published with the standard dual-package layout has its entry point in
|
|
120
|
+
* `dist/` beside a name-less `{"type":"module"}` stub, so walking up one
|
|
121
|
+
* directory from the entry file finds the wrong `package.json` entirely (see
|
|
122
|
+
* that port method's own doc comment). Carried as the PATH rather than a
|
|
123
|
+
* parsed `version`, so the one command that shows a version reads it lazily
|
|
124
|
+
* and `--help`/dispatch, which never show one, pay nothing for a field they
|
|
125
|
+
* do not use.
|
|
126
|
+
*/
|
|
127
|
+
interface InstalledPlugin {
|
|
128
|
+
readonly packageName: string;
|
|
129
|
+
readonly packageJsonPath: string;
|
|
130
|
+
readonly plugin: Plugin;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* `discover`'s result: every collection is always an array, never
|
|
134
|
+
* `null`/`undefined`.
|
|
135
|
+
*
|
|
136
|
+
* `plugins` is exactly `installed.map((entry) => entry.plugin)`, derived once
|
|
137
|
+
* inside `discover` so the two can never disagree. It stays alongside
|
|
138
|
+
* `installed` because the three callers that dispatch or render a plugin -
|
|
139
|
+
* `runPlugin`, `buildHelp` and the `init` wizard - want the `Plugin` and
|
|
140
|
+
* nothing else, and should not have to unwrap an envelope to serve the one
|
|
141
|
+
* caller (`blogwright plugin list`) that also names the package it came from.
|
|
142
|
+
*/
|
|
143
|
+
export interface DiscoveryResult {
|
|
144
|
+
readonly plugins: readonly Plugin[];
|
|
145
|
+
readonly installed: readonly InstalledPlugin[];
|
|
146
|
+
readonly failures: readonly PluginLoadFailure[];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Discover every installed plugin reachable from `repoRoot` (the consuming
|
|
150
|
+
* repo) and `cliPackageDir` (the CLI's own package directory, from
|
|
151
|
+
* {@link cliPackageDir} in `context.ts`). Never throws for a candidate-level
|
|
152
|
+
* problem - see the module comment - only for the two repo-level
|
|
153
|
+
* preconditions `collectCandidates` reads first.
|
|
154
|
+
*/
|
|
155
|
+
export declare function discover(repoRoot: string, cliPackageDir: string, ports: Pick<Ports, 'fs' | 'loader'>): Promise<DiscoveryResult>;
|
|
156
|
+
/**
|
|
157
|
+
* Resolve the config block ONE plugin owns into the value the dispatcher puts
|
|
158
|
+
* on `ctx.pluginConfig` - `runPlugin`'s single call, made for the plugin
|
|
159
|
+
* being DISPATCHED and no other (see the module comment's task-19 DECISION
|
|
160
|
+
* for why the scope is one plugin rather than every discovered one).
|
|
161
|
+
*
|
|
162
|
+
* The block is read off the RAW config document (`OpsContext.configDocument`,
|
|
163
|
+
* `context.ts`), never off `OpsConfig`, which has no index signature to reach
|
|
164
|
+
* a plugin's key through. `pluginBlock` returning `unknown` and the plugin's
|
|
165
|
+
* own `validateConfig` narrowing it is the sanctioned boundary: the very next
|
|
166
|
+
* step after the read validates it.
|
|
167
|
+
*
|
|
168
|
+
* The validator IS called when the plugin's key is ABSENT from the document,
|
|
169
|
+
* with `undefined`. That is the whole point of it: a validator is the only
|
|
170
|
+
* thing that can turn an absent block into the plugin's own defaults, and a
|
|
171
|
+
* repo that installs a plugin without writing its block is a valid,
|
|
172
|
+
* documented configuration. Handing `{}` straight through instead would put a
|
|
173
|
+
* block on `ctx.pluginConfig` that never went through the plugin's own
|
|
174
|
+
* defaulting - typed as total, `undefined` at runtime in every defaulted
|
|
175
|
+
* field - and nothing downstream could catch it, because the dispatcher
|
|
176
|
+
* erases `TConfig` (`Plugin<unknown>`, `PluginContext<unknown>`).
|
|
177
|
+
*
|
|
178
|
+
* `{}` is returned ONLY where there is no validator to call: a plugin that
|
|
179
|
+
* declares no `configKey` (a `Plugin<never>`, which cannot read
|
|
180
|
+
* `pluginConfig` at all) or no `validateConfig` - probed with `typeof ===
|
|
181
|
+
* 'function'`, the way this module and `plugin-commands.ts` both probe the
|
|
182
|
+
* `init` contributor, because core's `validatePlugin` type-checks neither
|
|
183
|
+
* member. `pluginConfig` is a required member, so `undefined` is not an
|
|
184
|
+
* option there - DEVELOPMENT.md's no-null rule.
|
|
185
|
+
*
|
|
186
|
+
* A validator's own rejection is re-raised with the plugin's name and the key
|
|
187
|
+
* in front of it and the plugin's message VERBATIM behind it, so an operator
|
|
188
|
+
* reading `blogwright analytics bootstrap`'s failure learns which plugin
|
|
189
|
+
* refused which key without the plugin having to name itself in every message
|
|
190
|
+
* it writes. It propagates - never swallowed, never downgraded to a warning -
|
|
191
|
+
* and exits non-zero through `bin.ts`'s error path.
|
|
192
|
+
*/
|
|
193
|
+
export declare function resolvePluginConfig(plugin: Plugin<unknown>, configDocument: Readonly<Record<string, unknown>>): unknown;
|
|
194
|
+
export {};
|