@spinabot/brigade 1.3.1 → 1.4.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 +54 -10
- package/convex/config.d.ts +2 -2
- package/convex/extensions.d.ts +2 -2
- package/convex/logs.d.ts +2 -2
- package/convex/memory.d.ts +7 -7
- package/convex/messages.d.ts +4 -4
- package/convex/schema.d.ts +17 -17
- package/convex/subagents.d.ts +12 -12
- package/dist/agents/agent-loop.d.ts +1 -0
- package/dist/agents/agent-loop.d.ts.map +1 -1
- package/dist/agents/agent-loop.js +1 -1
- package/dist/agents/agent-loop.js.map +1 -1
- package/dist/agents/channels/access-control/format-allow-from.d.ts +50 -0
- package/dist/agents/channels/access-control/format-allow-from.d.ts.map +1 -0
- package/dist/agents/channels/access-control/format-allow-from.js +64 -0
- package/dist/agents/channels/access-control/format-allow-from.js.map +1 -0
- package/dist/agents/channels/access-control/index.d.ts +2 -1
- package/dist/agents/channels/access-control/index.d.ts.map +1 -1
- package/dist/agents/channels/access-control/index.js +2 -1
- package/dist/agents/channels/access-control/index.js.map +1 -1
- package/dist/agents/channels/access-control/store.d.ts +15 -0
- package/dist/agents/channels/access-control/store.d.ts.map +1 -1
- package/dist/agents/channels/access-control/store.js +44 -1
- package/dist/agents/channels/access-control/store.js.map +1 -1
- package/dist/agents/channels/bundled-channel-metas.d.ts +26 -0
- package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -0
- package/dist/agents/channels/bundled-channel-metas.js +44 -0
- package/dist/agents/channels/bundled-channel-metas.js.map +1 -0
- package/dist/agents/channels/channel-messaging-registry.d.ts +130 -0
- package/dist/agents/channels/channel-messaging-registry.d.ts.map +1 -0
- package/dist/agents/channels/channel-messaging-registry.js +211 -0
- package/dist/agents/channels/channel-messaging-registry.js.map +1 -0
- package/dist/agents/channels/channel-meta-registry.d.ts +60 -0
- package/dist/agents/channels/channel-meta-registry.d.ts.map +1 -0
- package/dist/agents/channels/channel-meta-registry.js +128 -0
- package/dist/agents/channels/channel-meta-registry.js.map +1 -0
- package/dist/agents/channels/channel-security-registry.d.ts +138 -0
- package/dist/agents/channels/channel-security-registry.d.ts.map +1 -0
- package/dist/agents/channels/channel-security-registry.js +265 -0
- package/dist/agents/channels/channel-security-registry.js.map +1 -0
- package/dist/agents/channels/exposure.d.ts +44 -0
- package/dist/agents/channels/exposure.d.ts.map +1 -0
- package/dist/agents/channels/exposure.js +48 -0
- package/dist/agents/channels/exposure.js.map +1 -0
- package/dist/agents/channels/general-callback.d.ts +25 -0
- package/dist/agents/channels/general-callback.d.ts.map +1 -0
- package/dist/agents/channels/general-callback.js +31 -0
- package/dist/agents/channels/general-callback.js.map +1 -0
- package/dist/agents/channels/inbound-pipeline.d.ts +9 -0
- package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
- package/dist/agents/channels/inbound-pipeline.js +429 -39
- package/dist/agents/channels/inbound-pipeline.js.map +1 -1
- package/dist/agents/channels/markdown-capability.d.ts +44 -0
- package/dist/agents/channels/markdown-capability.d.ts.map +1 -0
- package/dist/agents/channels/markdown-capability.js +66 -0
- package/dist/agents/channels/markdown-capability.js.map +1 -0
- package/dist/agents/channels/sdk.d.ts +170 -10
- package/dist/agents/channels/sdk.d.ts.map +1 -1
- package/dist/agents/channels/sdk.js +138 -6
- package/dist/agents/channels/sdk.js.map +1 -1
- package/dist/agents/channels/telegram/account-config.d.ts +41 -0
- package/dist/agents/channels/telegram/account-config.d.ts.map +1 -1
- package/dist/agents/channels/telegram/account-config.js +79 -0
- package/dist/agents/channels/telegram/account-config.js.map +1 -1
- package/dist/agents/channels/telegram/adapter.d.ts +6 -0
- package/dist/agents/channels/telegram/adapter.d.ts.map +1 -1
- package/dist/agents/channels/telegram/adapter.js +178 -6
- package/dist/agents/channels/telegram/adapter.js.map +1 -1
- package/dist/agents/channels/telegram/allowed-updates.d.ts +14 -5
- package/dist/agents/channels/telegram/allowed-updates.d.ts.map +1 -1
- package/dist/agents/channels/telegram/allowed-updates.js +8 -4
- package/dist/agents/channels/telegram/allowed-updates.js.map +1 -1
- package/dist/agents/channels/telegram/connection.d.ts +108 -1
- package/dist/agents/channels/telegram/connection.d.ts.map +1 -1
- package/dist/agents/channels/telegram/connection.js +219 -3
- package/dist/agents/channels/telegram/connection.js.map +1 -1
- package/dist/agents/channels/telegram/draft-stream.d.ts +98 -0
- package/dist/agents/channels/telegram/draft-stream.d.ts.map +1 -0
- package/dist/agents/channels/telegram/draft-stream.js +222 -0
- package/dist/agents/channels/telegram/draft-stream.js.map +1 -0
- package/dist/agents/channels/telegram/inbound-extras.d.ts +10 -1
- package/dist/agents/channels/telegram/inbound-extras.d.ts.map +1 -1
- package/dist/agents/channels/telegram/inbound-extras.js +66 -0
- package/dist/agents/channels/telegram/inbound-extras.js.map +1 -1
- package/dist/agents/channels/telegram/inline-keyboard.d.ts +36 -0
- package/dist/agents/channels/telegram/inline-keyboard.d.ts.map +1 -0
- package/dist/agents/channels/telegram/inline-keyboard.js +62 -0
- package/dist/agents/channels/telegram/inline-keyboard.js.map +1 -0
- package/dist/agents/channels/telegram/plugin.d.ts.map +1 -1
- package/dist/agents/channels/telegram/plugin.js +7 -11
- package/dist/agents/channels/telegram/plugin.js.map +1 -1
- package/dist/agents/channels/telegram/reasoning-lane.d.ts +41 -0
- package/dist/agents/channels/telegram/reasoning-lane.d.ts.map +1 -0
- package/dist/agents/channels/telegram/reasoning-lane.js +67 -0
- package/dist/agents/channels/telegram/reasoning-lane.js.map +1 -0
- package/dist/agents/channels/telegram/socks-dispatcher.d.ts +32 -0
- package/dist/agents/channels/telegram/socks-dispatcher.d.ts.map +1 -0
- package/dist/agents/channels/telegram/socks-dispatcher.js +97 -0
- package/dist/agents/channels/telegram/socks-dispatcher.js.map +1 -0
- package/dist/agents/channels/types.adapters.d.ts +137 -4
- package/dist/agents/channels/types.adapters.d.ts.map +1 -1
- package/dist/agents/channels/types.adapters.js +2 -2
- package/dist/agents/channels/types.core.d.ts +26 -2
- package/dist/agents/channels/types.core.d.ts.map +1 -1
- package/dist/agents/channels/types.plugin.d.ts +25 -7
- package/dist/agents/channels/types.plugin.d.ts.map +1 -1
- package/dist/agents/channels/types.plugin.js +6 -5
- package/dist/agents/channels/types.plugin.js.map +1 -1
- package/dist/agents/channels/whatsapp/adapter.d.ts +8 -0
- package/dist/agents/channels/whatsapp/adapter.d.ts.map +1 -1
- package/dist/agents/channels/whatsapp/adapter.js +7 -4
- package/dist/agents/channels/whatsapp/adapter.js.map +1 -1
- package/dist/agents/channels/whatsapp/connection.d.ts +24 -2
- package/dist/agents/channels/whatsapp/connection.d.ts.map +1 -1
- package/dist/agents/channels/whatsapp/connection.js +26 -5
- package/dist/agents/channels/whatsapp/connection.js.map +1 -1
- package/dist/agents/channels/whatsapp/plugin.d.ts.map +1 -1
- package/dist/agents/channels/whatsapp/plugin.js +6 -10
- package/dist/agents/channels/whatsapp/plugin.js.map +1 -1
- package/dist/agents/extensions/activation-planner.d.ts +125 -0
- package/dist/agents/extensions/activation-planner.d.ts.map +1 -0
- package/dist/agents/extensions/activation-planner.js +221 -0
- package/dist/agents/extensions/activation-planner.js.map +1 -0
- package/dist/agents/extensions/diagnose.d.ts +84 -0
- package/dist/agents/extensions/diagnose.d.ts.map +1 -0
- package/dist/agents/extensions/diagnose.js +123 -0
- package/dist/agents/extensions/diagnose.js.map +1 -0
- package/dist/agents/extensions/discovery.d.ts +85 -7
- package/dist/agents/extensions/discovery.d.ts.map +1 -1
- package/dist/agents/extensions/discovery.js +200 -15
- package/dist/agents/extensions/discovery.js.map +1 -1
- package/dist/agents/extensions/index.d.ts +3 -2
- package/dist/agents/extensions/index.d.ts.map +1 -1
- package/dist/agents/extensions/index.js +3 -2
- package/dist/agents/extensions/index.js.map +1 -1
- package/dist/agents/extensions/install-scan.d.ts +63 -0
- package/dist/agents/extensions/install-scan.d.ts.map +1 -0
- package/dist/agents/extensions/install-scan.js +201 -0
- package/dist/agents/extensions/install-scan.js.map +1 -0
- package/dist/agents/extensions/install.d.ts +135 -0
- package/dist/agents/extensions/install.d.ts.map +1 -0
- package/dist/agents/extensions/install.js +414 -0
- package/dist/agents/extensions/install.js.map +1 -0
- package/dist/agents/extensions/loader.d.ts +13 -2
- package/dist/agents/extensions/loader.d.ts.map +1 -1
- package/dist/agents/extensions/loader.js +126 -13
- package/dist/agents/extensions/loader.js.map +1 -1
- package/dist/agents/extensions/registry.d.ts +109 -0
- package/dist/agents/extensions/registry.d.ts.map +1 -1
- package/dist/agents/extensions/registry.js +172 -0
- package/dist/agents/extensions/registry.js.map +1 -1
- package/dist/agents/extensions/sdk-alias.d.ts +45 -0
- package/dist/agents/extensions/sdk-alias.d.ts.map +1 -0
- package/dist/agents/extensions/sdk-alias.js +94 -0
- package/dist/agents/extensions/sdk-alias.js.map +1 -0
- package/dist/agents/extensions/types.d.ts +155 -1
- package/dist/agents/extensions/types.d.ts.map +1 -1
- package/dist/agents/extensions/types.js.map +1 -1
- package/dist/agents/tools/composio-tool.d.ts +9 -1
- package/dist/agents/tools/composio-tool.d.ts.map +1 -1
- package/dist/agents/tools/composio-tool.js +68 -4
- package/dist/agents/tools/composio-tool.js.map +1 -1
- package/dist/agents/tools/message-action-tool.d.ts +6 -1
- package/dist/agents/tools/message-action-tool.d.ts.map +1 -1
- package/dist/agents/tools/message-action-tool.js +52 -2
- package/dist/agents/tools/message-action-tool.js.map +1 -1
- package/dist/agents/tools/send-message-tool.d.ts +1 -0
- package/dist/agents/tools/send-message-tool.d.ts.map +1 -1
- package/dist/agents/tools/send-message-tool.js +56 -1
- package/dist/agents/tools/send-message-tool.js.map +1 -1
- package/dist/buildstamp.json +1 -1
- package/dist/channel-sdk.d.ts +28 -0
- package/dist/channel-sdk.d.ts.map +1 -0
- package/dist/channel-sdk.js +28 -0
- package/dist/channel-sdk.js.map +1 -0
- package/dist/cli/commands/channels.d.ts.map +1 -1
- package/dist/cli/commands/channels.js +8 -8
- package/dist/cli/commands/channels.js.map +1 -1
- package/dist/cli/commands/connect.d.ts +8 -11
- package/dist/cli/commands/connect.d.ts.map +1 -1
- package/dist/cli/commands/connect.js +157 -17
- package/dist/cli/commands/connect.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +64 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/extensions.d.ts +46 -0
- package/dist/cli/commands/extensions.d.ts.map +1 -0
- package/dist/cli/commands/extensions.js +578 -0
- package/dist/cli/commands/extensions.js.map +1 -0
- package/dist/cli/commands/gateway.d.ts.map +1 -1
- package/dist/cli/commands/gateway.js +6 -0
- package/dist/cli/commands/gateway.js.map +1 -1
- package/dist/cli/commands/pairing.d.ts.map +1 -1
- package/dist/cli/commands/pairing.js +16 -2
- package/dist/cli/commands/pairing.js.map +1 -1
- package/dist/cli/commands/update.d.ts +17 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.js +104 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/program/build-program.d.ts.map +1 -1
- package/dist/cli/program/build-program.js +113 -0
- package/dist/cli/program/build-program.js.map +1 -1
- package/dist/config/paths.d.ts +1 -0
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +9 -0
- package/dist/config/paths.js.map +1 -1
- package/dist/core/gateway-probe.d.ts.map +1 -1
- package/dist/core/gateway-probe.js +9 -1
- package/dist/core/gateway-probe.js.map +1 -1
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +134 -2
- package/dist/core/server.js.map +1 -1
- package/dist/protocol.d.ts +25 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/dist/system-prompt/assembler.d.ts.map +1 -1
- package/dist/system-prompt/assembler.js +17 -0
- package/dist/system-prompt/assembler.js.map +1 -1
- package/dist/system-prompt/identity-defaults.d.ts +28 -0
- package/dist/system-prompt/identity-defaults.d.ts.map +1 -1
- package/dist/system-prompt/identity-defaults.js +47 -0
- package/dist/system-prompt/identity-defaults.js.map +1 -1
- package/dist/ui/editor.d.ts.map +1 -1
- package/dist/ui/editor.js +1 -0
- package/dist/ui/editor.js.map +1 -1
- package/dist/version.d.ts +4 -3
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +27 -5
- package/dist/version.js.map +1 -1
- package/package.json +21 -4
- package/scripts/build-done.mjs +11 -2
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension install / remove engine — the source-agnostic machinery behind
|
|
3
|
+
* `brigade extensions add <source>` and `brigade extensions remove <id>`.
|
|
4
|
+
*
|
|
5
|
+
* `add` brings a third-party module into `~/.brigade/extensions/<id>/` from one
|
|
6
|
+
* of three source forms:
|
|
7
|
+
* • a LOCAL PATH (a folder or a single file) → copied in;
|
|
8
|
+
* • an NPM SPEC (`name`, `name@version`, `@scope/name@1.2.3`) → fetched with
|
|
9
|
+
* `npm pack` into a temp dir, unpacked, and moved in (npm only — never pnpm);
|
|
10
|
+
* • a GIT URL (`https://…/repo.git`, `git@…`, `git+…`) → cloned in.
|
|
11
|
+
*
|
|
12
|
+
* The installed module's id is resolved from its `brigade.extension.json`
|
|
13
|
+
* manifest id, else its `package.json` name, else the source basename. An
|
|
14
|
+
* existing id is refused unless `force` is set.
|
|
15
|
+
*
|
|
16
|
+
* After the files land, two read-only gates run:
|
|
17
|
+
* 1. COMPAT — read the installed manifest and compare `minBrigadeVersion` /
|
|
18
|
+
* `pluginApi` against the running build. A module that needs a NEWER
|
|
19
|
+
* Brigade is refused (the only hard failure here); a missing field is
|
|
20
|
+
* lenient (compatible).
|
|
21
|
+
* 2. SCAN — `install-scan.ts` does a static dual-use pattern sweep. Findings
|
|
22
|
+
* are SURFACED, never auto-blocking; the CLI asks the operator to ack.
|
|
23
|
+
*
|
|
24
|
+
* This module does the filesystem + compat work and RETURNS a structured result;
|
|
25
|
+
* the CLI layer (`commands/extensions.ts`) owns all rendering + the interactive
|
|
26
|
+
* scan acknowledgement. Keeping the two apart lets the install logic be unit-
|
|
27
|
+
* tested against a tempdir source with no TTY + no network.
|
|
28
|
+
*/
|
|
29
|
+
import { type ScanReport } from "./install-scan.js";
|
|
30
|
+
import type { BrigadeModuleManifest } from "./types.js";
|
|
31
|
+
/** Which kind of source `add` resolved the argument to. */
|
|
32
|
+
export type InstallSourceKind = "local" | "npm" | "git";
|
|
33
|
+
/** Verdict from the compat (version) gate. */
|
|
34
|
+
export interface CompatVerdict {
|
|
35
|
+
/** True when the module is safe to run on this Brigade build. */
|
|
36
|
+
compatible: boolean;
|
|
37
|
+
/** Running Brigade version (for display). */
|
|
38
|
+
brigadeVersion: string;
|
|
39
|
+
/** The module's declared minimum Brigade version, when it set one. */
|
|
40
|
+
minBrigadeVersion?: string;
|
|
41
|
+
/** The module's declared plugin-API generation, when it set one. */
|
|
42
|
+
pluginApi?: string;
|
|
43
|
+
/** One operator-facing line — why it's (in)compatible. */
|
|
44
|
+
reason: string;
|
|
45
|
+
}
|
|
46
|
+
/** Everything the CLI needs to render a completed install. */
|
|
47
|
+
export interface InstallResult {
|
|
48
|
+
/** Resolved extension id (the folder name under the extensions dir). */
|
|
49
|
+
id: string;
|
|
50
|
+
/** Absolute folder the module landed in. */
|
|
51
|
+
dir: string;
|
|
52
|
+
/** How the source argument was classified. */
|
|
53
|
+
sourceKind: InstallSourceKind;
|
|
54
|
+
/** The original source argument, echoed back. */
|
|
55
|
+
source: string;
|
|
56
|
+
/** Installed manifest, when the module shipped a sidecar. */
|
|
57
|
+
manifest?: BrigadeModuleManifest;
|
|
58
|
+
/** Compat (version) verdict. */
|
|
59
|
+
compat: CompatVerdict;
|
|
60
|
+
/** Static security-scan report. */
|
|
61
|
+
scan: ScanReport;
|
|
62
|
+
/** True when `--force` overwrote a pre-existing extension of the same id. */
|
|
63
|
+
replacedExisting: boolean;
|
|
64
|
+
}
|
|
65
|
+
/** A thrown install failure carrying an operator-facing message. */
|
|
66
|
+
export declare class InstallError extends Error {
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The plugin-API generation THIS Brigade build implements. Bumped only on a
|
|
70
|
+
* breaking change to the module/SDK contract. A module whose manifest
|
|
71
|
+
* `pluginApi` is a higher integer than this targets a future Brigade and is
|
|
72
|
+
* refused by the compat gate.
|
|
73
|
+
*/
|
|
74
|
+
export declare const CURRENT_PLUGIN_API = 1;
|
|
75
|
+
/**
|
|
76
|
+
* Classify the source argument. A path that exists on disk is always `local`
|
|
77
|
+
* (so a folder literally named like a package still installs from disk); then
|
|
78
|
+
* git URLs; then everything else is treated as an npm spec.
|
|
79
|
+
*/
|
|
80
|
+
export declare function classifySource(source: string): InstallSourceKind;
|
|
81
|
+
/**
|
|
82
|
+
* Normalise an arbitrary string into a safe extensions-folder id: lowercase,
|
|
83
|
+
* `[a-z0-9-]`, no leading digit-only weirdness. Mirrors the `init` id rules
|
|
84
|
+
* loosely (we accept what we can sanitise rather than reject).
|
|
85
|
+
*/
|
|
86
|
+
export declare function sanitizeId(raw: string): string;
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the target id for an extracted/staged module: manifest id wins, then
|
|
89
|
+
* package.json name, then the supplied `fallback` (source basename). All run
|
|
90
|
+
* through `sanitizeId`.
|
|
91
|
+
*/
|
|
92
|
+
export declare function resolveModuleId(stagedDir: string, fallback: string): string;
|
|
93
|
+
/**
|
|
94
|
+
* Decide whether a module (by its manifest) is compatible with the running
|
|
95
|
+
* Brigade. Lenient by design: a module that declares neither field is always
|
|
96
|
+
* compatible. The two hard-fail cases are forward-incompatibility — the module
|
|
97
|
+
* needs a NEWER Brigade than this build, or targets a NEWER plugin-API
|
|
98
|
+
* generation than this build implements.
|
|
99
|
+
*
|
|
100
|
+
* `brigadeVersionOverride` / `pluginApiOverride` are test seams.
|
|
101
|
+
*/
|
|
102
|
+
export declare function checkCompat(manifest: BrigadeModuleManifest | undefined, brigadeVersionOverride?: string, pluginApiOverride?: number): CompatVerdict;
|
|
103
|
+
export interface InstallOptions {
|
|
104
|
+
/** The extensions dir to install into (`~/.brigade/extensions` in prod). */
|
|
105
|
+
extensionsDir: string;
|
|
106
|
+
/** Overwrite an existing extension of the same id. */
|
|
107
|
+
force?: boolean;
|
|
108
|
+
/** Test seam — override the running Brigade version for the compat gate. */
|
|
109
|
+
brigadeVersionOverride?: string;
|
|
110
|
+
/** Test seam — override the plugin-API generation for the compat gate. */
|
|
111
|
+
pluginApiOverride?: number;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Install an extension from a source. Does NOT prompt — it stages, resolves the
|
|
115
|
+
* id, refuses an existing id unless `force`, copies the module into place, then
|
|
116
|
+
* runs the compat + scan gates and returns the structured result. The CLI layer
|
|
117
|
+
* decides whether to keep it (e.g. after the operator acks the scan). The
|
|
118
|
+
* compat gate is the one hard failure: a forward-incompatible module is
|
|
119
|
+
* REMOVED again and an `InstallError` is thrown.
|
|
120
|
+
*/
|
|
121
|
+
export declare function installExtension(source: string, opts: InstallOptions): Promise<InstallResult>;
|
|
122
|
+
/** Outcome of a remove. */
|
|
123
|
+
export interface RemoveResult {
|
|
124
|
+
id: string;
|
|
125
|
+
dir: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Remove an installed extension by id. Refuses cleanly (throws `InstallError`)
|
|
129
|
+
* when no extension of that id is installed. `id` is sanitised the same way
|
|
130
|
+
* install resolves it, so `remove My-Plugin` matches the `my-plugin` folder.
|
|
131
|
+
*/
|
|
132
|
+
export declare function removeExtension(id: string, extensionsDir: string): RemoveResult;
|
|
133
|
+
/** List installed extension ids (folder names) under the extensions dir. */
|
|
134
|
+
export declare function listInstalledIds(extensionsDir: string): string[];
|
|
135
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/agents/extensions/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAiBH,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAIxD,2DAA2D;AAC3D,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,CAAC;AAExD,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC7B,iEAAiE;IACjE,UAAU,EAAE,OAAO,CAAC;IACpB,6CAA6C;IAC7C,cAAc,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;CACf;AAED,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC7B,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,UAAU,EAAE,iBAAiB,CAAC;IAC9B,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,gCAAgC;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,mCAAmC;IACnC,IAAI,EAAE,UAAU,CAAC;IACjB,6EAA6E;IAC7E,gBAAgB,EAAE,OAAO,CAAC;CAC1B;AAED,oEAAoE;AACpE,qBAAa,YAAa,SAAQ,KAAK;CAAG;AAI1C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAcpC;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAchE;AAqDD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQ9C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAc3E;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAC1B,QAAQ,EAAE,qBAAqB,GAAG,SAAS,EAC3C,sBAAsB,CAAC,EAAE,MAAM,EAC/B,iBAAiB,CAAC,EAAE,MAAM,GACxB,aAAa,CA2Cf;AAiFD,MAAM,WAAW,cAAc;IAC9B,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,0EAA0E;IAC1E,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAyDnG;AAED,2BAA2B;AAC3B,MAAM,WAAW,YAAY;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,YAAY,CAe/E;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,CAehE"}
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension install / remove engine — the source-agnostic machinery behind
|
|
3
|
+
* `brigade extensions add <source>` and `brigade extensions remove <id>`.
|
|
4
|
+
*
|
|
5
|
+
* `add` brings a third-party module into `~/.brigade/extensions/<id>/` from one
|
|
6
|
+
* of three source forms:
|
|
7
|
+
* • a LOCAL PATH (a folder or a single file) → copied in;
|
|
8
|
+
* • an NPM SPEC (`name`, `name@version`, `@scope/name@1.2.3`) → fetched with
|
|
9
|
+
* `npm pack` into a temp dir, unpacked, and moved in (npm only — never pnpm);
|
|
10
|
+
* • a GIT URL (`https://…/repo.git`, `git@…`, `git+…`) → cloned in.
|
|
11
|
+
*
|
|
12
|
+
* The installed module's id is resolved from its `brigade.extension.json`
|
|
13
|
+
* manifest id, else its `package.json` name, else the source basename. An
|
|
14
|
+
* existing id is refused unless `force` is set.
|
|
15
|
+
*
|
|
16
|
+
* After the files land, two read-only gates run:
|
|
17
|
+
* 1. COMPAT — read the installed manifest and compare `minBrigadeVersion` /
|
|
18
|
+
* `pluginApi` against the running build. A module that needs a NEWER
|
|
19
|
+
* Brigade is refused (the only hard failure here); a missing field is
|
|
20
|
+
* lenient (compatible).
|
|
21
|
+
* 2. SCAN — `install-scan.ts` does a static dual-use pattern sweep. Findings
|
|
22
|
+
* are SURFACED, never auto-blocking; the CLI asks the operator to ack.
|
|
23
|
+
*
|
|
24
|
+
* This module does the filesystem + compat work and RETURNS a structured result;
|
|
25
|
+
* the CLI layer (`commands/extensions.ts`) owns all rendering + the interactive
|
|
26
|
+
* scan acknowledgement. Keeping the two apart lets the install logic be unit-
|
|
27
|
+
* tested against a tempdir source with no TTY + no network.
|
|
28
|
+
*/
|
|
29
|
+
import { execFileSync } from "node:child_process";
|
|
30
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, } from "node:fs";
|
|
31
|
+
import { tmpdir } from "node:os";
|
|
32
|
+
import path from "node:path";
|
|
33
|
+
import { getBuildInfo } from "../../version.js";
|
|
34
|
+
import { scanInstalledModule } from "./install-scan.js";
|
|
35
|
+
const SIDECAR_BASENAME = "brigade.extension.json";
|
|
36
|
+
/** A thrown install failure carrying an operator-facing message. */
|
|
37
|
+
export class InstallError extends Error {
|
|
38
|
+
}
|
|
39
|
+
/* ─────────────────────────── plugin-API generation ─────────────────────────── */
|
|
40
|
+
/**
|
|
41
|
+
* The plugin-API generation THIS Brigade build implements. Bumped only on a
|
|
42
|
+
* breaking change to the module/SDK contract. A module whose manifest
|
|
43
|
+
* `pluginApi` is a higher integer than this targets a future Brigade and is
|
|
44
|
+
* refused by the compat gate.
|
|
45
|
+
*/
|
|
46
|
+
export const CURRENT_PLUGIN_API = 1;
|
|
47
|
+
/* ─────────────────────────── source classification ─────────────────────────── */
|
|
48
|
+
/** Does the argument look like a git URL we should clone? */
|
|
49
|
+
function isGitUrl(source) {
|
|
50
|
+
return (/^git\+/.test(source) ||
|
|
51
|
+
/^git@/.test(source) ||
|
|
52
|
+
/^(?:https?|git|ssh):\/\/.*\.git(?:#.*)?$/.test(source) ||
|
|
53
|
+
/^(?:https?:\/\/)?(?:www\.)?(?:github|gitlab|bitbucket)\.com\/[^/]+\/[^/]+/.test(source));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Classify the source argument. A path that exists on disk is always `local`
|
|
57
|
+
* (so a folder literally named like a package still installs from disk); then
|
|
58
|
+
* git URLs; then everything else is treated as an npm spec.
|
|
59
|
+
*/
|
|
60
|
+
export function classifySource(source) {
|
|
61
|
+
const trimmed = source.trim();
|
|
62
|
+
if (trimmed.length === 0)
|
|
63
|
+
throw new InstallError("No source given. Pass a folder, a file, an npm package, or a git URL.");
|
|
64
|
+
// An on-disk path always wins — unambiguous + offline.
|
|
65
|
+
try {
|
|
66
|
+
if (existsSync(trimmed))
|
|
67
|
+
return "local";
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* fall through to remote classification */
|
|
71
|
+
}
|
|
72
|
+
// Explicit relative/absolute path markers that don't (yet) exist → still local
|
|
73
|
+
// (the install step then reports "no such file" clearly rather than trying npm).
|
|
74
|
+
if (/^[.~]/.test(trimmed) || path.isAbsolute(trimmed))
|
|
75
|
+
return "local";
|
|
76
|
+
if (isGitUrl(trimmed))
|
|
77
|
+
return "git";
|
|
78
|
+
return "npm";
|
|
79
|
+
}
|
|
80
|
+
/* ─────────────────────────── manifest + id resolution ─────────────────────────── */
|
|
81
|
+
/** Read + parse a JSON file, returning `undefined` on any failure. */
|
|
82
|
+
function readJson(file) {
|
|
83
|
+
try {
|
|
84
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
85
|
+
return parsed && typeof parsed === "object" ? parsed : undefined;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Find + read the sidecar manifest at the root of an installed/extracted module. */
|
|
92
|
+
function readManifestAt(dir) {
|
|
93
|
+
const sidecar = path.join(dir, SIDECAR_BASENAME);
|
|
94
|
+
const parsed = readJson(sidecar);
|
|
95
|
+
if (parsed && typeof parsed.id === "string")
|
|
96
|
+
return parsed;
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
/** Read a `package.json` `name` at the root of a module, when present. */
|
|
100
|
+
function readPackageName(dir) {
|
|
101
|
+
const parsed = readJson(path.join(dir, "package.json"));
|
|
102
|
+
const name = parsed?.name;
|
|
103
|
+
return typeof name === "string" && name.length > 0 ? name : undefined;
|
|
104
|
+
}
|
|
105
|
+
/** Strip an npm scope + version range to a bare, folder-safe id. */
|
|
106
|
+
function bareNameFromSpec(spec) {
|
|
107
|
+
// `@scope/name@1.2.3` → `name`; `name@^2` → `name`; `name` → `name`.
|
|
108
|
+
let s = spec.trim();
|
|
109
|
+
// Drop a trailing version range (the LAST `@` that isn't the scope `@`).
|
|
110
|
+
const at = s.lastIndexOf("@");
|
|
111
|
+
if (at > 0)
|
|
112
|
+
s = s.slice(0, at);
|
|
113
|
+
// Drop the scope prefix.
|
|
114
|
+
if (s.startsWith("@")) {
|
|
115
|
+
const slash = s.indexOf("/");
|
|
116
|
+
if (slash >= 0)
|
|
117
|
+
s = s.slice(slash + 1);
|
|
118
|
+
}
|
|
119
|
+
return s;
|
|
120
|
+
}
|
|
121
|
+
/** Strip a git URL down to its repo basename (sans `.git` + fragment). */
|
|
122
|
+
function repoNameFromGit(url) {
|
|
123
|
+
let s = url.trim().replace(/^git\+/, "");
|
|
124
|
+
s = s.split("#")[0] ?? s; // drop a `#branch` fragment
|
|
125
|
+
s = s.replace(/\/+$/, ""); // trailing slashes
|
|
126
|
+
const last = s.split(/[/:]/).pop() ?? s;
|
|
127
|
+
return last.replace(/\.git$/i, "");
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Normalise an arbitrary string into a safe extensions-folder id: lowercase,
|
|
131
|
+
* `[a-z0-9-]`, no leading digit-only weirdness. Mirrors the `init` id rules
|
|
132
|
+
* loosely (we accept what we can sanitise rather than reject).
|
|
133
|
+
*/
|
|
134
|
+
export function sanitizeId(raw) {
|
|
135
|
+
const cleaned = raw
|
|
136
|
+
.trim()
|
|
137
|
+
.toLowerCase()
|
|
138
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
139
|
+
.replace(/-+/g, "-")
|
|
140
|
+
.replace(/^-+|-+$/g, "");
|
|
141
|
+
return cleaned;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Resolve the target id for an extracted/staged module: manifest id wins, then
|
|
145
|
+
* package.json name, then the supplied `fallback` (source basename). All run
|
|
146
|
+
* through `sanitizeId`.
|
|
147
|
+
*/
|
|
148
|
+
export function resolveModuleId(stagedDir, fallback) {
|
|
149
|
+
const manifest = readManifestAt(stagedDir);
|
|
150
|
+
if (manifest?.id) {
|
|
151
|
+
const id = sanitizeId(manifest.id);
|
|
152
|
+
if (id)
|
|
153
|
+
return id;
|
|
154
|
+
}
|
|
155
|
+
const pkgName = readPackageName(stagedDir);
|
|
156
|
+
if (pkgName) {
|
|
157
|
+
const id = sanitizeId(bareNameFromSpec(pkgName));
|
|
158
|
+
if (id)
|
|
159
|
+
return id;
|
|
160
|
+
}
|
|
161
|
+
const id = sanitizeId(fallback);
|
|
162
|
+
if (id)
|
|
163
|
+
return id;
|
|
164
|
+
throw new InstallError("Couldn't work out a name for this extension. Give it one by adding a brigade.extension.json with an \"id\".");
|
|
165
|
+
}
|
|
166
|
+
/* ─────────────────────────── compat (version) gate ─────────────────────────── */
|
|
167
|
+
/** Parse a leading `major.minor.patch` from a version string → numeric tuple. */
|
|
168
|
+
function parseSemverLead(v) {
|
|
169
|
+
const m = /^\s*v?(\d+)(?:\.(\d+))?(?:\.(\d+))?/.exec(v);
|
|
170
|
+
if (!m)
|
|
171
|
+
return null;
|
|
172
|
+
return [Number(m[1] ?? 0), Number(m[2] ?? 0), Number(m[3] ?? 0)];
|
|
173
|
+
}
|
|
174
|
+
/** Compare two semver leads: -1 / 0 / 1. */
|
|
175
|
+
function compareSemver(a, b) {
|
|
176
|
+
for (let i = 0; i < 3; i++) {
|
|
177
|
+
const av = a[i] ?? 0;
|
|
178
|
+
const bv = b[i] ?? 0;
|
|
179
|
+
if (av !== bv)
|
|
180
|
+
return av < bv ? -1 : 1;
|
|
181
|
+
}
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Decide whether a module (by its manifest) is compatible with the running
|
|
186
|
+
* Brigade. Lenient by design: a module that declares neither field is always
|
|
187
|
+
* compatible. The two hard-fail cases are forward-incompatibility — the module
|
|
188
|
+
* needs a NEWER Brigade than this build, or targets a NEWER plugin-API
|
|
189
|
+
* generation than this build implements.
|
|
190
|
+
*
|
|
191
|
+
* `brigadeVersionOverride` / `pluginApiOverride` are test seams.
|
|
192
|
+
*/
|
|
193
|
+
export function checkCompat(manifest, brigadeVersionOverride, pluginApiOverride) {
|
|
194
|
+
const brigadeVersion = brigadeVersionOverride ?? getBuildInfo().version;
|
|
195
|
+
const currentApi = pluginApiOverride ?? CURRENT_PLUGIN_API;
|
|
196
|
+
const minBrigadeVersion = manifest?.minBrigadeVersion;
|
|
197
|
+
const pluginApi = manifest?.pluginApi;
|
|
198
|
+
// (1) plugin-API generation — a forward-incompatible module targets a newer
|
|
199
|
+
// generation than this build understands.
|
|
200
|
+
if (typeof pluginApi === "string" && pluginApi.trim().length > 0) {
|
|
201
|
+
const wanted = Number.parseInt(pluginApi.trim(), 10);
|
|
202
|
+
if (Number.isFinite(wanted) && wanted > currentApi) {
|
|
203
|
+
return {
|
|
204
|
+
compatible: false,
|
|
205
|
+
brigadeVersion,
|
|
206
|
+
minBrigadeVersion,
|
|
207
|
+
pluginApi,
|
|
208
|
+
reason: `This extension targets plugin API v${wanted}, but this Brigade only supports up to v${currentApi}. Update Brigade first.`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// (2) minimum Brigade version — module needs a newer Brigade than is running.
|
|
213
|
+
if (typeof minBrigadeVersion === "string" && minBrigadeVersion.trim().length > 0) {
|
|
214
|
+
const need = parseSemverLead(minBrigadeVersion);
|
|
215
|
+
const have = parseSemverLead(brigadeVersion);
|
|
216
|
+
if (need && have && compareSemver(have, need) < 0) {
|
|
217
|
+
return {
|
|
218
|
+
compatible: false,
|
|
219
|
+
brigadeVersion,
|
|
220
|
+
minBrigadeVersion,
|
|
221
|
+
pluginApi,
|
|
222
|
+
reason: `This extension needs Brigade ${minBrigadeVersion} or newer; you're on ${brigadeVersion}. Update Brigade first.`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
compatible: true,
|
|
228
|
+
brigadeVersion,
|
|
229
|
+
minBrigadeVersion,
|
|
230
|
+
pluginApi,
|
|
231
|
+
reason: "Compatible with this version of Brigade.",
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/* ─────────────────────────── staging by source kind ─────────────────────────── */
|
|
235
|
+
/** Copy a local path (file OR folder) into a fresh staging dir; return it. */
|
|
236
|
+
function stageLocal(source, stageRoot) {
|
|
237
|
+
const abs = path.resolve(source.replace(/^~(?=$|[/\\])/, () => process.env.HOME ?? process.env.USERPROFILE ?? "~"));
|
|
238
|
+
let st;
|
|
239
|
+
try {
|
|
240
|
+
st = statSync(abs);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
throw new InstallError(`No file or folder found at ${abs}.`);
|
|
244
|
+
}
|
|
245
|
+
const stagedDir = path.join(stageRoot, "staged");
|
|
246
|
+
mkdirSync(stagedDir, { recursive: true });
|
|
247
|
+
if (st.isDirectory()) {
|
|
248
|
+
cpSync(abs, stagedDir, { recursive: true });
|
|
249
|
+
return { stagedDir, fallbackName: path.basename(abs) };
|
|
250
|
+
}
|
|
251
|
+
// Single file → place it as the module's index, preserving its extension.
|
|
252
|
+
const ext = path.extname(abs) || ".js";
|
|
253
|
+
const indexName = `index${ext}`;
|
|
254
|
+
cpSync(abs, path.join(stagedDir, indexName));
|
|
255
|
+
return { stagedDir, fallbackName: path.basename(abs, ext) };
|
|
256
|
+
}
|
|
257
|
+
/** Run a command, surfacing a clean error. `cwd` defaults to the stage root. */
|
|
258
|
+
function runTool(cmd, args, cwd) {
|
|
259
|
+
try {
|
|
260
|
+
execFileSync(cmd, args, { cwd, stdio: "pipe", windowsHide: true });
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
264
|
+
throw new InstallError(`\`${cmd} ${args.join(" ")}\` failed: ${detail}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/** Fetch an npm package via `npm pack`, unpack the tarball, return the dir. */
|
|
268
|
+
function stageNpm(spec, stageRoot) {
|
|
269
|
+
// `npm pack <spec>` downloads the tarball into cwd and prints its filename.
|
|
270
|
+
let out;
|
|
271
|
+
try {
|
|
272
|
+
out = execFileSync("npm", ["pack", spec, "--silent"], {
|
|
273
|
+
cwd: stageRoot,
|
|
274
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
275
|
+
encoding: "utf8",
|
|
276
|
+
windowsHide: true,
|
|
277
|
+
}).trim();
|
|
278
|
+
}
|
|
279
|
+
catch (err) {
|
|
280
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
281
|
+
throw new InstallError(`Couldn't download "${spec}" from npm: ${detail}`);
|
|
282
|
+
}
|
|
283
|
+
// `npm pack` may print multiple lines; the tarball name is the last non-empty.
|
|
284
|
+
const tarball = out.split(/\r?\n/).map((l) => l.trim()).filter(Boolean).pop();
|
|
285
|
+
if (!tarball)
|
|
286
|
+
throw new InstallError(`npm didn't produce a package tarball for "${spec}".`);
|
|
287
|
+
const tarballPath = path.join(stageRoot, tarball);
|
|
288
|
+
const extractDir = path.join(stageRoot, "unpacked");
|
|
289
|
+
mkdirSync(extractDir, { recursive: true });
|
|
290
|
+
// Tarballs from `npm pack` always nest under a top-level `package/` dir.
|
|
291
|
+
runTool("tar", ["-xzf", tarballPath, "-C", extractDir], stageRoot);
|
|
292
|
+
const inner = path.join(extractDir, "package");
|
|
293
|
+
const stagedDir = existsSync(inner) ? inner : extractDir;
|
|
294
|
+
return { stagedDir, fallbackName: bareNameFromSpec(spec) };
|
|
295
|
+
}
|
|
296
|
+
/** Clone a git URL (shallow) into a staging dir; return it. */
|
|
297
|
+
function stageGit(url, stageRoot) {
|
|
298
|
+
const stagedDir = path.join(stageRoot, "cloned");
|
|
299
|
+
const cleanUrl = url.replace(/^git\+/, "");
|
|
300
|
+
runTool("git", ["clone", "--depth", "1", cleanUrl, stagedDir], stageRoot);
|
|
301
|
+
// Drop the `.git` dir so it isn't carried into the extensions folder (and
|
|
302
|
+
// doesn't trip the scanner's skip rules either way).
|
|
303
|
+
try {
|
|
304
|
+
rmSync(path.join(stagedDir, ".git"), { recursive: true, force: true });
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
/* best-effort */
|
|
308
|
+
}
|
|
309
|
+
return { stagedDir, fallbackName: repoNameFromGit(url) };
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Install an extension from a source. Does NOT prompt — it stages, resolves the
|
|
313
|
+
* id, refuses an existing id unless `force`, copies the module into place, then
|
|
314
|
+
* runs the compat + scan gates and returns the structured result. The CLI layer
|
|
315
|
+
* decides whether to keep it (e.g. after the operator acks the scan). The
|
|
316
|
+
* compat gate is the one hard failure: a forward-incompatible module is
|
|
317
|
+
* REMOVED again and an `InstallError` is thrown.
|
|
318
|
+
*/
|
|
319
|
+
export async function installExtension(source, opts) {
|
|
320
|
+
const sourceKind = classifySource(source);
|
|
321
|
+
const stageRoot = mkdtempSync(path.join(tmpdir(), "brigade-ext-install-"));
|
|
322
|
+
try {
|
|
323
|
+
// 1. Stage the bytes into a temp dir based on the source kind.
|
|
324
|
+
const staged = sourceKind === "local"
|
|
325
|
+
? stageLocal(source, stageRoot)
|
|
326
|
+
: sourceKind === "npm"
|
|
327
|
+
? stageNpm(source, stageRoot)
|
|
328
|
+
: stageGit(source, stageRoot);
|
|
329
|
+
// 2. Resolve the id (manifest → package.json → basename).
|
|
330
|
+
const id = resolveModuleId(staged.stagedDir, staged.fallbackName);
|
|
331
|
+
// 3. Collision check.
|
|
332
|
+
const targetDir = path.join(opts.extensionsDir, id);
|
|
333
|
+
const exists = existsSync(targetDir);
|
|
334
|
+
if (exists && !opts.force) {
|
|
335
|
+
throw new InstallError(`An extension named "${id}" is already installed. Re-run with --force to replace it, or remove it first with \`brigade extensions remove ${id}\`.`);
|
|
336
|
+
}
|
|
337
|
+
// 4. Copy the staged module into the extensions dir.
|
|
338
|
+
mkdirSync(opts.extensionsDir, { recursive: true });
|
|
339
|
+
if (exists)
|
|
340
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
341
|
+
cpSync(staged.stagedDir, targetDir, { recursive: true });
|
|
342
|
+
// 5. Compat gate — the one hard failure. Roll back on incompatibility.
|
|
343
|
+
const manifest = readManifestAt(targetDir);
|
|
344
|
+
const compat = checkCompat(manifest, opts.brigadeVersionOverride, opts.pluginApiOverride);
|
|
345
|
+
if (!compat.compatible) {
|
|
346
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
347
|
+
throw new InstallError(compat.reason);
|
|
348
|
+
}
|
|
349
|
+
// 6. Security scan — surfaced, never auto-blocking.
|
|
350
|
+
const scan = scanInstalledModule(targetDir);
|
|
351
|
+
return {
|
|
352
|
+
id,
|
|
353
|
+
dir: targetDir,
|
|
354
|
+
sourceKind,
|
|
355
|
+
source,
|
|
356
|
+
manifest,
|
|
357
|
+
compat,
|
|
358
|
+
scan,
|
|
359
|
+
replacedExisting: exists,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
finally {
|
|
363
|
+
try {
|
|
364
|
+
rmSync(stageRoot, { recursive: true, force: true });
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
/* best-effort temp cleanup */
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Remove an installed extension by id. Refuses cleanly (throws `InstallError`)
|
|
373
|
+
* when no extension of that id is installed. `id` is sanitised the same way
|
|
374
|
+
* install resolves it, so `remove My-Plugin` matches the `my-plugin` folder.
|
|
375
|
+
*/
|
|
376
|
+
export function removeExtension(id, extensionsDir) {
|
|
377
|
+
const safeId = sanitizeId(id);
|
|
378
|
+
if (!safeId)
|
|
379
|
+
throw new InstallError(`"${id}" isn't a valid extension name.`);
|
|
380
|
+
const dir = path.join(extensionsDir, safeId);
|
|
381
|
+
let isDir = false;
|
|
382
|
+
try {
|
|
383
|
+
isDir = statSync(dir).isDirectory();
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
isDir = false;
|
|
387
|
+
}
|
|
388
|
+
if (!isDir) {
|
|
389
|
+
throw new InstallError(`No extension named "${safeId}" is installed. Run \`brigade extensions list\` to see what you have.`);
|
|
390
|
+
}
|
|
391
|
+
rmSync(dir, { recursive: true, force: true });
|
|
392
|
+
return { id: safeId, dir };
|
|
393
|
+
}
|
|
394
|
+
/** List installed extension ids (folder names) under the extensions dir. */
|
|
395
|
+
export function listInstalledIds(extensionsDir) {
|
|
396
|
+
try {
|
|
397
|
+
return readdirSync(extensionsDir)
|
|
398
|
+
.filter((name) => {
|
|
399
|
+
if (name.startsWith("."))
|
|
400
|
+
return false;
|
|
401
|
+
try {
|
|
402
|
+
return statSync(path.join(extensionsDir, name)).isDirectory();
|
|
403
|
+
}
|
|
404
|
+
catch {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
})
|
|
408
|
+
.sort();
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
return [];
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/agents/extensions/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,8 +12,19 @@
|
|
|
12
12
|
* Activation traceability: EVERY module decision (activated / skipped) emits a
|
|
13
13
|
* structured log line under the `extensions/loader` subsystem. The reason is a
|
|
14
14
|
* stable enum (`disabled`/`requiresEnv`/`eligible`/`allowlist`/`configSchema`/
|
|
15
|
-
* `registerFailed`) so an operator running
|
|
16
|
-
* JSONL log can answer "why didn't my plugin
|
|
15
|
+
* `registerFailed`/`activation-not-triggered`) so an operator running
|
|
16
|
+
* `brigade doctor` or scraping the JSONL log can answer "why didn't my plugin
|
|
17
|
+
* load" without source-diving.
|
|
18
|
+
*
|
|
19
|
+
* Step 5 — manifest-driven LAZY activation. User modules are no longer imported
|
|
20
|
+
* eagerly. The loader lists candidates WITHOUT importing, reads each one's
|
|
21
|
+
* sidecar `brigade.extension.json` manifest, and consults the activation planner
|
|
22
|
+
* (`activation-planner.ts`) against an active-config snapshot. A module whose
|
|
23
|
+
* declared `activation` triggers don't fire is NEVER imported (its top-level
|
|
24
|
+
* never runs) — O(manifest) boot. A module with no sidecar manifest is imported
|
|
25
|
+
* to recover its `manifest` field, then re-planned from the body, so back-compat
|
|
26
|
+
* holds (no manifest / no triggers ⇒ always activate). Skips here log
|
|
27
|
+
* `reason=activation-not-triggered`.
|
|
17
28
|
*/
|
|
18
29
|
import { BrigadeExtensionRegistry, type RegistryContextMeta } from "./registry.js";
|
|
19
30
|
import type { BrigadeModule } from "./types.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/agents/extensions/loader.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/agents/extensions/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAkBH,OAAO,EAAE,wBAAwB,EAAqB,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACtG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAmChD,MAAM,WAAW,eAAe;IAC/B,yCAAyC;IACzC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gFAAgF;IAChF,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAkBD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAiM1F"}
|