@kolisachint/hoocode-agent 0.5.7 → 0.5.9
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 +100 -0
- package/dist/{modes/interactive → core}/brand.d.ts +6 -0
- package/dist/core/brand.d.ts.map +1 -0
- package/dist/{modes/interactive → core}/brand.js +6 -0
- package/dist/core/brand.js.map +1 -0
- package/dist/core/extensions/plugins/listing.d.ts +34 -0
- package/dist/core/extensions/plugins/listing.d.ts.map +1 -0
- package/dist/core/extensions/plugins/listing.js +69 -0
- package/dist/core/extensions/plugins/listing.js.map +1 -0
- package/dist/core/extensions/types.d.ts +9 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/format-list.d.ts +101 -0
- package/dist/core/format-list.d.ts.map +1 -0
- package/dist/core/format-list.js +171 -0
- package/dist/core/format-list.js.map +1 -0
- package/dist/core/skills.d.ts +9 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +9 -0
- package/dist/core/skills.js.map +1 -1
- package/dist/core/tools/plugins.d.ts.map +1 -1
- package/dist/core/tools/plugins.js +93 -28
- package/dist/core/tools/plugins.js.map +1 -1
- package/dist/extensions/core/marketplace.d.ts.map +1 -1
- package/dist/extensions/core/marketplace.js +61 -13
- package/dist/extensions/core/marketplace.js.map +1 -1
- package/dist/modes/interactive/components/ask-options.d.ts.map +1 -1
- package/dist/modes/interactive/components/ask-options.js +6 -6
- package/dist/modes/interactive/components/ask-options.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +5 -4
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +11 -7
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +9 -16
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +7 -12
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +6 -3
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/selected-row-list.d.ts +28 -0
- package/dist/modes/interactive/components/selected-row-list.d.ts.map +1 -0
- package/dist/modes/interactive/components/selected-row-list.js +37 -0
- package/dist/modes/interactive/components/selected-row-list.js.map +1 -0
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +4 -7
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +4 -7
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +6 -4
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +24 -3
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/resource-display.d.ts +2 -0
- package/dist/modes/interactive/resource-display.d.ts.map +1 -1
- package/dist/modes/interactive/resource-display.js +10 -7
- package/dist/modes/interactive/resource-display.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +24 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +32 -1
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
- package/dist/modes/interactive/brand.d.ts.map +0 -1
- package/dist/modes/interactive/brand.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,105 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.9] - 2026-08-12
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- The session tree selector's highlight stopped wherever the entry text
|
|
8
|
+
stopped, because the row was wrapped in `selectedBg` without being padded
|
|
9
|
+
first — a 17-cell band on a 120-column terminal. It now fills the row, like
|
|
10
|
+
the `/resume` picker beside it.
|
|
11
|
+
- The resource picker (`/config`) marked its selected row with bold alone — no
|
|
12
|
+
accent, no highlight — which on a light theme was close to invisible. It now
|
|
13
|
+
carries the same accent and band as every other picker.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **The selected row is highlighted the same way in more of the app.** Until now
|
|
18
|
+
only the `/resume` session picker filled its selected row with `selectedBg`;
|
|
19
|
+
every other picker marked selection with an arrow and accent text alone, and
|
|
20
|
+
the band in `/resume` reached the right edge only because that component
|
|
21
|
+
right-aligns a timestamp column. `getSelectListTheme()` and
|
|
22
|
+
`getSettingsListTheme()` now supply a `selectedRow` background, so the theme
|
|
23
|
+
picker, thinking picker, show-images picker, the `/settings` screens and the
|
|
24
|
+
editor's autocomplete all draw the same full-width highlight. The accent
|
|
25
|
+
styling stays: `accent` clears 4.6:1 against `selectedBg` in every shipped
|
|
26
|
+
theme, while `muted` and `dim` fall to 2.8:1 and 1.9:1 on `dark`, so the band
|
|
27
|
+
is added to the existing marker rather than replacing it. The hand-rolled
|
|
28
|
+
pickers now do the same, via `SelectedRowList` (below).
|
|
29
|
+
- **Every picker marks its selected row with the same cursor.** `→`, `›` and
|
|
30
|
+
`>` were all in use — four glyphs counting the one `SelectList` hardcoded —
|
|
31
|
+
so which one you saw depended on which list you had opened. They all use `›`
|
|
32
|
+
now, from a single `SELECT_CURSOR`. In the ask-for-input pane this also stops
|
|
33
|
+
the row cursor colliding with the `>` that prompts its custom-answer field.
|
|
34
|
+
- Unselected rows are indented by `SELECT_GUTTER`, derived from the cursor's
|
|
35
|
+
visible width, rather than by a hardcoded two columns. The two agreed before
|
|
36
|
+
only because every cursor in use happened to be two columns wide.
|
|
37
|
+
- The model, scoped models, oauth and extension pickers build their rows
|
|
38
|
+
through the new `SelectedRowList` component instead of adding a `Text` child
|
|
39
|
+
per row. Those rows were assembled in an update method that never sees the
|
|
40
|
+
terminal width — width only arrives later, when the container renders each
|
|
41
|
+
child — so there was no point at which a row could be padded before being
|
|
42
|
+
painted. `SelectedRowList` holds the rows and renders them lazily, which puts
|
|
43
|
+
the width back in reach.
|
|
44
|
+
- The fork-from-message picker highlights the message line the cursor is on
|
|
45
|
+
(its metadata line stays unpainted) and colors it with `accent`, which it
|
|
46
|
+
previously left to bold alone.
|
|
47
|
+
- The ask-for-input pane keeps its plain rows: it is a question form with a
|
|
48
|
+
live text field, not a scrolling list, and a band under an input caret reads
|
|
49
|
+
as a rendering artifact rather than a selection.
|
|
50
|
+
- The `/resume` session picker and the session tree selector paint their
|
|
51
|
+
selected row through a shared `paintSelectedRow` helper rather than each
|
|
52
|
+
calling `theme.bg` on a row they had padded (or not padded) themselves.
|
|
53
|
+
`/resume` no longer depends on its right-aligned timestamp column to reach
|
|
54
|
+
the right edge.
|
|
55
|
+
|
|
56
|
+
## [0.5.8] - 2026-08-12
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
|
|
60
|
+
- **Capability listings share one layout.** `/plugin list`,
|
|
61
|
+
`/plugin marketplace list`, `SearchPlugins` and `ListPlugins` each built their
|
|
62
|
+
own `name [a, b] — description` line, so the same plugin printed three ways
|
|
63
|
+
and the model's view never matched the user's. They now go through a single
|
|
64
|
+
row formatter (`core/format-list.ts`, `core/extensions/plugins/listing.ts`):
|
|
65
|
+
aligned name column, facts beside it, description wrapped with a hanging
|
|
66
|
+
indent instead of restarting at column 0, and plugins grouped by the
|
|
67
|
+
marketplace that offers them. `/plugin list` marks what is already installed.
|
|
68
|
+
- `SearchPlugins` takes a `limit` (default 10). With no query it previously
|
|
69
|
+
returned every plugin in every registered marketplace — dozens of entries,
|
|
70
|
+
several lines each — into the chat and the context.
|
|
71
|
+
- The five plugin tools define `renderResult`, as every other built-in tool
|
|
72
|
+
already did. Results are bounded to 20 lines with an expand hint rather than
|
|
73
|
+
dumped whole.
|
|
74
|
+
- `ListPlugins` reports the manifest format its description already promised,
|
|
75
|
+
counts `themes` and `providers` as capabilities (a plugin shipping only a
|
|
76
|
+
theme reported none), and carries the plugin description through.
|
|
77
|
+
- `[Agents]` in the startup summary is one line per agent, truncated to the
|
|
78
|
+
terminal, instead of a 200-character summary wrapping into a paragraph.
|
|
79
|
+
- `brand.ts` moved to `core/` so non-interactive surfaces can label capability
|
|
80
|
+
classes; added a `marketplaces` glyph.
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
- Status messages carrying their own colors are no longer wrapped in a blanket
|
|
85
|
+
dim. `theme.fg` closes with `\x1b[39m` (reset, not restore), so the dim died
|
|
86
|
+
at the first inner span and — because the wrapper carries that state across
|
|
87
|
+
newlines — every line after it lost the dim too.
|
|
88
|
+
- `InstallPlugin` no longer erases its own announcement. It notified "installing
|
|
89
|
+
X because Y", then notified the outcome; consecutive info notifications
|
|
90
|
+
coalesce into one chat line, so the second replaced the first and the
|
|
91
|
+
transparency the tool guidelines require never reached the screen.
|
|
92
|
+
- Truncation in the new listings does not emit escape codes. The TUI's
|
|
93
|
+
`truncateToWidth` appends `\x1b[0m` even for plain input — a full reset that
|
|
94
|
+
would both leak into model-facing text and clear any enclosing style mid-line.
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
|
|
98
|
+
- `ExtensionUIContext.columns` exposes the terminal width to extensions, so a
|
|
99
|
+
listing can wrap to the actual terminal. Optional, and undefined outside a
|
|
100
|
+
terminal (RPC, print), which is the signal to emit unwrapped text rather than
|
|
101
|
+
wrap to someone else's width.
|
|
102
|
+
|
|
3
103
|
## [0.5.7] - 2026-08-12
|
|
4
104
|
|
|
5
105
|
### Added
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
* Glyphs are chosen to be single terminal cell, widely supported, and distinct
|
|
12
12
|
* from the task-panel's own status/owner glyphs (◐ ◆ ◇ ▸ ⧉ ✓ ✗ ○) so the two
|
|
13
13
|
* vocabularies never read as the same signal.
|
|
14
|
+
*
|
|
15
|
+
* This lives in `core/` rather than `modes/interactive/` because the `/plugin`
|
|
16
|
+
* command extension labels the same capability classes, and extensions must not
|
|
17
|
+
* reach into a mode's internals. The module is pure data — no theme, no
|
|
18
|
+
* rendering — so it is safe for every surface.
|
|
14
19
|
*/
|
|
15
20
|
/** The HooCode mark — a filled hexagon, rendered in the accent colour. */
|
|
16
21
|
export declare const BRAND_MARK = "\u2B22";
|
|
@@ -25,6 +30,7 @@ export declare const CATEGORY_GLYPH: {
|
|
|
25
30
|
readonly agents: "◈";
|
|
26
31
|
readonly mcp: "⧉";
|
|
27
32
|
readonly plugins: "⬡";
|
|
33
|
+
readonly marketplaces: "⊞";
|
|
28
34
|
readonly themes: "◒";
|
|
29
35
|
readonly context: "❯";
|
|
30
36
|
readonly extensions: "⊹";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.d.ts","sourceRoot":"","sources":["../../src/core/brand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,4EAA0E;AAC1E,eAAO,MAAM,UAAU,WAAM,CAAC;AAE9B;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;CAUjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,cAAc,CAAC;AAEtD,iEAAiE;AACjE,eAAO,MAAM,WAAW,WAAM,CAAC;AAE/B,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,WAAM,CAAC","sourcesContent":["/**\n * HooCode brand identity — the single source of truth for the product mark and\n * the glyph vocabulary the interactive surfaces share.\n *\n * The brand *colour* is the theme's `accent` token (see theme/dark.json,\n * theme/light.json) so it stays theme-aware and swappable; this module owns the\n * non-colour identity: the mark and the category glyphs used by the footer,\n * the startup resource summary, and anywhere a capability class is labelled.\n * Keeping them here means a future rebrand touches one file, not twenty.\n *\n * Glyphs are chosen to be single terminal cell, widely supported, and distinct\n * from the task-panel's own status/owner glyphs (◐ ◆ ◇ ▸ ⧉ ✓ ✗ ○) so the two\n * vocabularies never read as the same signal.\n *\n * This lives in `core/` rather than `modes/interactive/` because the `/plugin`\n * command extension labels the same capability classes, and extensions must not\n * reach into a mode's internals. The module is pure data — no theme, no\n * rendering — so it is safe for every surface.\n */\n\n/** The HooCode mark — a filled hexagon, rendered in the accent colour. */\nexport const BRAND_MARK = \"⬢\";\n\n/**\n * Glyphs for the capability classes a session can load. Used by the startup\n * \"resources ready\" summary and reusable anywhere a class needs a label. Each is\n * a single cell so counts and columns stay aligned.\n */\nexport const CATEGORY_GLYPH = {\n\tskills: \"✦\",\n\tcommands: \"⌘\",\n\tagents: \"◈\",\n\tmcp: \"⧉\",\n\tplugins: \"⬡\",\n\tmarketplaces: \"⊞\",\n\tthemes: \"◒\",\n\tcontext: \"❯\",\n\textensions: \"⊹\",\n} as const;\n\nexport type CategoryKey = keyof typeof CATEGORY_GLYPH;\n\n/** A soft dot separator used between footer/summary segments. */\nexport const SEGMENT_SEP = \"·\";\n\n/** Fork glyph preceding a git branch. */\nexport const GIT_BRANCH_GLYPH = \"⑂\";\n"]}
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
* Glyphs are chosen to be single terminal cell, widely supported, and distinct
|
|
12
12
|
* from the task-panel's own status/owner glyphs (◐ ◆ ◇ ▸ ⧉ ✓ ✗ ○) so the two
|
|
13
13
|
* vocabularies never read as the same signal.
|
|
14
|
+
*
|
|
15
|
+
* This lives in `core/` rather than `modes/interactive/` because the `/plugin`
|
|
16
|
+
* command extension labels the same capability classes, and extensions must not
|
|
17
|
+
* reach into a mode's internals. The module is pure data — no theme, no
|
|
18
|
+
* rendering — so it is safe for every surface.
|
|
14
19
|
*/
|
|
15
20
|
/** The HooCode mark — a filled hexagon, rendered in the accent colour. */
|
|
16
21
|
export const BRAND_MARK = "⬢";
|
|
@@ -25,6 +30,7 @@ export const CATEGORY_GLYPH = {
|
|
|
25
30
|
agents: "◈",
|
|
26
31
|
mcp: "⧉",
|
|
27
32
|
plugins: "⬡",
|
|
33
|
+
marketplaces: "⊞",
|
|
28
34
|
themes: "◒",
|
|
29
35
|
context: "❯",
|
|
30
36
|
extensions: "⊹",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.js","sourceRoot":"","sources":["../../src/core/brand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,4EAA0E;AAC1E,MAAM,CAAC,MAAM,UAAU,GAAG,KAAG,CAAC;AAE9B;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC7B,MAAM,EAAE,KAAG;IACX,QAAQ,EAAE,KAAG;IACb,MAAM,EAAE,KAAG;IACX,GAAG,EAAE,KAAG;IACR,OAAO,EAAE,KAAG;IACZ,YAAY,EAAE,KAAG;IACjB,MAAM,EAAE,KAAG;IACX,OAAO,EAAE,KAAG;IACZ,UAAU,EAAE,KAAG;CACN,CAAC;AAIX,iEAAiE;AACjE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAG,CAAC;AAE/B,yCAAyC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAG,CAAC","sourcesContent":["/**\n * HooCode brand identity — the single source of truth for the product mark and\n * the glyph vocabulary the interactive surfaces share.\n *\n * The brand *colour* is the theme's `accent` token (see theme/dark.json,\n * theme/light.json) so it stays theme-aware and swappable; this module owns the\n * non-colour identity: the mark and the category glyphs used by the footer,\n * the startup resource summary, and anywhere a capability class is labelled.\n * Keeping them here means a future rebrand touches one file, not twenty.\n *\n * Glyphs are chosen to be single terminal cell, widely supported, and distinct\n * from the task-panel's own status/owner glyphs (◐ ◆ ◇ ▸ ⧉ ✓ ✗ ○) so the two\n * vocabularies never read as the same signal.\n *\n * This lives in `core/` rather than `modes/interactive/` because the `/plugin`\n * command extension labels the same capability classes, and extensions must not\n * reach into a mode's internals. The module is pure data — no theme, no\n * rendering — so it is safe for every surface.\n */\n\n/** The HooCode mark — a filled hexagon, rendered in the accent colour. */\nexport const BRAND_MARK = \"⬢\";\n\n/**\n * Glyphs for the capability classes a session can load. Used by the startup\n * \"resources ready\" summary and reusable anywhere a class needs a label. Each is\n * a single cell so counts and columns stay aligned.\n */\nexport const CATEGORY_GLYPH = {\n\tskills: \"✦\",\n\tcommands: \"⌘\",\n\tagents: \"◈\",\n\tmcp: \"⧉\",\n\tplugins: \"⬡\",\n\tmarketplaces: \"⊞\",\n\tthemes: \"◒\",\n\tcontext: \"❯\",\n\textensions: \"⊹\",\n} as const;\n\nexport type CategoryKey = keyof typeof CATEGORY_GLYPH;\n\n/** A soft dot separator used between footer/summary segments. */\nexport const SEGMENT_SEP = \"·\";\n\n/** Fork glyph preceding a git branch. */\nexport const GIT_BRANCH_GLYPH = \"⑂\";\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row shapes for the plugin listings, shared by every surface that prints one.
|
|
3
|
+
*
|
|
4
|
+
* `/plugin list`, `SearchPlugins` and `ListPlugins` describe the same objects,
|
|
5
|
+
* and each used to build its own `name [a, b] — description` string, so the same
|
|
6
|
+
* plugin printed three ways and the model's view never quite matched the user's.
|
|
7
|
+
* They all go through here now; only the styling and the width differ.
|
|
8
|
+
*/
|
|
9
|
+
import type { ListGroup, ListRow } from "../../format-list.js";
|
|
10
|
+
import type { AvailablePlugin } from "./install.js";
|
|
11
|
+
import type { NormalizedPlugin } from "./manifest.js";
|
|
12
|
+
/** Human-readable source for an available plugin (a URL, a path, an npm spec). */
|
|
13
|
+
export declare function formatPluginSource(source: AvailablePlugin["source"]): string;
|
|
14
|
+
/**
|
|
15
|
+
* Capability classes a plugin actually ships.
|
|
16
|
+
*
|
|
17
|
+
* Covers every capability `NormalizedPlugin` can carry — themes and providers
|
|
18
|
+
* included, which the old `ListPlugins` inline list omitted, so a plugin that
|
|
19
|
+
* shipped only a theme or only a provider reported no capabilities at all.
|
|
20
|
+
*/
|
|
21
|
+
export declare function pluginCapabilities(plugin: NormalizedPlugin): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Available plugins, grouped by the marketplace offering them.
|
|
24
|
+
*
|
|
25
|
+
* Grouping is what makes provenance legible: a flat list cannot answer "where
|
|
26
|
+
* would this come from if I installed it", which is the one question that
|
|
27
|
+
* matters at a trust boundary. Marketplace order is preserved from the caller.
|
|
28
|
+
*/
|
|
29
|
+
export declare function availablePluginGroups(plugins: readonly AvailablePlugin[], options?: {
|
|
30
|
+
installed?: ReadonlySet<string>;
|
|
31
|
+
}): ListGroup[];
|
|
32
|
+
/** Installed plugins as rows: id@version, platforms, format, capabilities. */
|
|
33
|
+
export declare function installedPluginRows(plugins: readonly NormalizedPlugin[]): ListRow[];
|
|
34
|
+
//# sourceMappingURL=listing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listing.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/listing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,GAAG,MAAM,CAI5E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAUrE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,SAAS,eAAe,EAAE,EACnC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAO,GAC/C,SAAS,EAAE,CAab;AAED,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,OAAO,EAAE,CAWnF","sourcesContent":["/**\n * Row shapes for the plugin listings, shared by every surface that prints one.\n *\n * `/plugin list`, `SearchPlugins` and `ListPlugins` describe the same objects,\n * and each used to build its own `name [a, b] — description` string, so the same\n * plugin printed three ways and the model's view never quite matched the user's.\n * They all go through here now; only the styling and the width differ.\n */\n\nimport type { ListGroup, ListRow } from \"../../format-list.js\";\nimport type { AvailablePlugin } from \"./install.js\";\nimport type { NormalizedPlugin } from \"./manifest.js\";\n\n/** Human-readable source for an available plugin (a URL, a path, an npm spec). */\nexport function formatPluginSource(source: AvailablePlugin[\"source\"]): string {\n\tif (typeof source === \"string\") return source;\n\tif (source.source === \"url\") return source.url;\n\treturn `${source.url}/${source.path}`;\n}\n\n/**\n * Capability classes a plugin actually ships.\n *\n * Covers every capability `NormalizedPlugin` can carry — themes and providers\n * included, which the old `ListPlugins` inline list omitted, so a plugin that\n * shipped only a theme or only a provider reported no capabilities at all.\n */\nexport function pluginCapabilities(plugin: NormalizedPlugin): string[] {\n\treturn [\n\t\tplugin.skillsDir && \"skills\",\n\t\tplugin.commandsDir && \"commands\",\n\t\tplugin.agentsDir && \"agents\",\n\t\tplugin.themesDir && \"themes\",\n\t\tplugin.hooks && \"hooks\",\n\t\tplugin.mcpServers && \"mcp\",\n\t\tplugin.providers?.length && \"providers\",\n\t].filter((value): value is string => typeof value === \"string\");\n}\n\n/**\n * Available plugins, grouped by the marketplace offering them.\n *\n * Grouping is what makes provenance legible: a flat list cannot answer \"where\n * would this come from if I installed it\", which is the one question that\n * matters at a trust boundary. Marketplace order is preserved from the caller.\n */\nexport function availablePluginGroups(\n\tplugins: readonly AvailablePlugin[],\n\toptions: { installed?: ReadonlySet<string> } = {},\n): ListGroup[] {\n\tconst groups = new Map<string, ListRow[]>();\n\tfor (const plugin of plugins) {\n\t\tconst rows = groups.get(plugin.marketplaceName) ?? [];\n\t\trows.push({\n\t\t\tname: plugin.name,\n\t\t\tmarker: options.installed?.has(plugin.name) ? \"✓\" : undefined,\n\t\t\tfacts: [plugin.supportPlatform.join(\"/\"), plugin.sourceKind],\n\t\t\tdetail: plugin.description ?? formatPluginSource(plugin.source),\n\t\t});\n\t\tgroups.set(plugin.marketplaceName, rows);\n\t}\n\treturn Array.from(groups, ([title, rows]) => ({ title, rows }));\n}\n\n/** Installed plugins as rows: id@version, platforms, format, capabilities. */\nexport function installedPluginRows(plugins: readonly NormalizedPlugin[]): ListRow[] {\n\treturn plugins.map((plugin) => {\n\t\tconst capabilities = pluginCapabilities(plugin);\n\t\treturn {\n\t\t\tname: `${plugin.id}${plugin.version ? `@${plugin.version}` : \"\"}`,\n\t\t\t// The manifest format is parenthesised because it is usually the same\n\t\t\t// word as the platform (\"claude/github · claude\" reads as a stutter).\n\t\t\tfacts: [plugin.supportPlatform.join(\"/\"), `(${plugin.format})`, capabilities.join(\", \") || \"no capabilities\"],\n\t\t\tdetail: plugin.description,\n\t\t};\n\t});\n}\n"]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row shapes for the plugin listings, shared by every surface that prints one.
|
|
3
|
+
*
|
|
4
|
+
* `/plugin list`, `SearchPlugins` and `ListPlugins` describe the same objects,
|
|
5
|
+
* and each used to build its own `name [a, b] — description` string, so the same
|
|
6
|
+
* plugin printed three ways and the model's view never quite matched the user's.
|
|
7
|
+
* They all go through here now; only the styling and the width differ.
|
|
8
|
+
*/
|
|
9
|
+
/** Human-readable source for an available plugin (a URL, a path, an npm spec). */
|
|
10
|
+
export function formatPluginSource(source) {
|
|
11
|
+
if (typeof source === "string")
|
|
12
|
+
return source;
|
|
13
|
+
if (source.source === "url")
|
|
14
|
+
return source.url;
|
|
15
|
+
return `${source.url}/${source.path}`;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Capability classes a plugin actually ships.
|
|
19
|
+
*
|
|
20
|
+
* Covers every capability `NormalizedPlugin` can carry — themes and providers
|
|
21
|
+
* included, which the old `ListPlugins` inline list omitted, so a plugin that
|
|
22
|
+
* shipped only a theme or only a provider reported no capabilities at all.
|
|
23
|
+
*/
|
|
24
|
+
export function pluginCapabilities(plugin) {
|
|
25
|
+
return [
|
|
26
|
+
plugin.skillsDir && "skills",
|
|
27
|
+
plugin.commandsDir && "commands",
|
|
28
|
+
plugin.agentsDir && "agents",
|
|
29
|
+
plugin.themesDir && "themes",
|
|
30
|
+
plugin.hooks && "hooks",
|
|
31
|
+
plugin.mcpServers && "mcp",
|
|
32
|
+
plugin.providers?.length && "providers",
|
|
33
|
+
].filter((value) => typeof value === "string");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Available plugins, grouped by the marketplace offering them.
|
|
37
|
+
*
|
|
38
|
+
* Grouping is what makes provenance legible: a flat list cannot answer "where
|
|
39
|
+
* would this come from if I installed it", which is the one question that
|
|
40
|
+
* matters at a trust boundary. Marketplace order is preserved from the caller.
|
|
41
|
+
*/
|
|
42
|
+
export function availablePluginGroups(plugins, options = {}) {
|
|
43
|
+
const groups = new Map();
|
|
44
|
+
for (const plugin of plugins) {
|
|
45
|
+
const rows = groups.get(plugin.marketplaceName) ?? [];
|
|
46
|
+
rows.push({
|
|
47
|
+
name: plugin.name,
|
|
48
|
+
marker: options.installed?.has(plugin.name) ? "✓" : undefined,
|
|
49
|
+
facts: [plugin.supportPlatform.join("/"), plugin.sourceKind],
|
|
50
|
+
detail: plugin.description ?? formatPluginSource(plugin.source),
|
|
51
|
+
});
|
|
52
|
+
groups.set(plugin.marketplaceName, rows);
|
|
53
|
+
}
|
|
54
|
+
return Array.from(groups, ([title, rows]) => ({ title, rows }));
|
|
55
|
+
}
|
|
56
|
+
/** Installed plugins as rows: id@version, platforms, format, capabilities. */
|
|
57
|
+
export function installedPluginRows(plugins) {
|
|
58
|
+
return plugins.map((plugin) => {
|
|
59
|
+
const capabilities = pluginCapabilities(plugin);
|
|
60
|
+
return {
|
|
61
|
+
name: `${plugin.id}${plugin.version ? `@${plugin.version}` : ""}`,
|
|
62
|
+
// The manifest format is parenthesised because it is usually the same
|
|
63
|
+
// word as the platform ("claude/github · claude" reads as a stutter).
|
|
64
|
+
facts: [plugin.supportPlatform.join("/"), `(${plugin.format})`, capabilities.join(", ") || "no capabilities"],
|
|
65
|
+
detail: plugin.description,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=listing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listing.js","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/listing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,kFAAkF;AAClF,MAAM,UAAU,kBAAkB,CAAC,MAAiC,EAAU;IAC7E,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC;IAC/C,OAAO,GAAG,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;AAAA,CACtC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAwB,EAAY;IACtE,OAAO;QACN,MAAM,CAAC,SAAS,IAAI,QAAQ;QAC5B,MAAM,CAAC,WAAW,IAAI,UAAU;QAChC,MAAM,CAAC,SAAS,IAAI,QAAQ;QAC5B,MAAM,CAAC,SAAS,IAAI,QAAQ;QAC5B,MAAM,CAAC,KAAK,IAAI,OAAO;QACvB,MAAM,CAAC,UAAU,IAAI,KAAK;QAC1B,MAAM,CAAC,SAAS,EAAE,MAAM,IAAI,WAAW;KACvC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;AAAA,CAChE;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACpC,OAAmC,EACnC,OAAO,GAAwC,EAAE,EACnC;IACd,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC5C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;QACtD,IAAI,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,MAAM,EAAE,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAG,CAAC,CAAC,CAAC,SAAS;YAC7D,KAAK,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;YAC5D,MAAM,EAAE,MAAM,CAAC,WAAW,IAAI,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC;SAC/D,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAAA,CAChE;AAED,8EAA8E;AAC9E,MAAM,UAAU,mBAAmB,CAAC,OAAoC,EAAa;IACpF,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAChD,OAAO;YACN,IAAI,EAAE,GAAG,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;YACjE,sEAAsE;YACtE,uEAAsE;YACtE,KAAK,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC;YAC7G,MAAM,EAAE,MAAM,CAAC,WAAW;SAC1B,CAAC;IAAA,CACF,CAAC,CAAC;AAAA,CACH","sourcesContent":["/**\n * Row shapes for the plugin listings, shared by every surface that prints one.\n *\n * `/plugin list`, `SearchPlugins` and `ListPlugins` describe the same objects,\n * and each used to build its own `name [a, b] — description` string, so the same\n * plugin printed three ways and the model's view never quite matched the user's.\n * They all go through here now; only the styling and the width differ.\n */\n\nimport type { ListGroup, ListRow } from \"../../format-list.js\";\nimport type { AvailablePlugin } from \"./install.js\";\nimport type { NormalizedPlugin } from \"./manifest.js\";\n\n/** Human-readable source for an available plugin (a URL, a path, an npm spec). */\nexport function formatPluginSource(source: AvailablePlugin[\"source\"]): string {\n\tif (typeof source === \"string\") return source;\n\tif (source.source === \"url\") return source.url;\n\treturn `${source.url}/${source.path}`;\n}\n\n/**\n * Capability classes a plugin actually ships.\n *\n * Covers every capability `NormalizedPlugin` can carry — themes and providers\n * included, which the old `ListPlugins` inline list omitted, so a plugin that\n * shipped only a theme or only a provider reported no capabilities at all.\n */\nexport function pluginCapabilities(plugin: NormalizedPlugin): string[] {\n\treturn [\n\t\tplugin.skillsDir && \"skills\",\n\t\tplugin.commandsDir && \"commands\",\n\t\tplugin.agentsDir && \"agents\",\n\t\tplugin.themesDir && \"themes\",\n\t\tplugin.hooks && \"hooks\",\n\t\tplugin.mcpServers && \"mcp\",\n\t\tplugin.providers?.length && \"providers\",\n\t].filter((value): value is string => typeof value === \"string\");\n}\n\n/**\n * Available plugins, grouped by the marketplace offering them.\n *\n * Grouping is what makes provenance legible: a flat list cannot answer \"where\n * would this come from if I installed it\", which is the one question that\n * matters at a trust boundary. Marketplace order is preserved from the caller.\n */\nexport function availablePluginGroups(\n\tplugins: readonly AvailablePlugin[],\n\toptions: { installed?: ReadonlySet<string> } = {},\n): ListGroup[] {\n\tconst groups = new Map<string, ListRow[]>();\n\tfor (const plugin of plugins) {\n\t\tconst rows = groups.get(plugin.marketplaceName) ?? [];\n\t\trows.push({\n\t\t\tname: plugin.name,\n\t\t\tmarker: options.installed?.has(plugin.name) ? \"✓\" : undefined,\n\t\t\tfacts: [plugin.supportPlatform.join(\"/\"), plugin.sourceKind],\n\t\t\tdetail: plugin.description ?? formatPluginSource(plugin.source),\n\t\t});\n\t\tgroups.set(plugin.marketplaceName, rows);\n\t}\n\treturn Array.from(groups, ([title, rows]) => ({ title, rows }));\n}\n\n/** Installed plugins as rows: id@version, platforms, format, capabilities. */\nexport function installedPluginRows(plugins: readonly NormalizedPlugin[]): ListRow[] {\n\treturn plugins.map((plugin) => {\n\t\tconst capabilities = pluginCapabilities(plugin);\n\t\treturn {\n\t\t\tname: `${plugin.id}${plugin.version ? `@${plugin.version}` : \"\"}`,\n\t\t\t// The manifest format is parenthesised because it is usually the same\n\t\t\t// word as the platform (\"claude/github · claude\" reads as a stutter).\n\t\t\tfacts: [plugin.supportPlatform.join(\"/\"), `(${plugin.format})`, capabilities.join(\", \") || \"no capabilities\"],\n\t\t\tdetail: plugin.description,\n\t\t};\n\t});\n}\n"]}
|
|
@@ -99,6 +99,15 @@ export interface ExtensionUIContext {
|
|
|
99
99
|
askOptions(questions: AskQuestion[], opts?: ExtensionUIDialogOptions): Promise<string[] | undefined>;
|
|
100
100
|
/** Show a notification to the user. */
|
|
101
101
|
notify(message: string, type?: "info" | "warning" | "error"): void;
|
|
102
|
+
/**
|
|
103
|
+
* Terminal width in columns, when the surface has one.
|
|
104
|
+
*
|
|
105
|
+
* Undefined outside a terminal (RPC, print, headless), which is the signal to
|
|
106
|
+
* emit unwrapped text and let the consumer lay it out — a listing pre-wrapped
|
|
107
|
+
* to someone else's terminal is worse than no wrapping at all. Optional so
|
|
108
|
+
* third-party implementations of this interface keep compiling.
|
|
109
|
+
*/
|
|
110
|
+
readonly columns?: number;
|
|
102
111
|
/** Listen to raw terminal input (interactive mode only). Returns an unsubscribe function. */
|
|
103
112
|
onTerminalInput(handler: TerminalInputHandler): () => void;
|
|
104
113
|
/** Set status text in the footer/status bar. Pass undefined to clear. */
|