@north-light/crouter 0.3.183 → 0.3.185

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.
Files changed (67) hide show
  1. package/dist/build-root.js +10 -3
  2. package/dist/builtin-memory/internal/plugins.md +1 -1
  3. package/dist/clients/attach/input/capabilities.js +3 -0
  4. package/dist/clients/attach/slash/dispatch.js +12 -0
  5. package/dist/clients/attach/viewer.js +191 -191
  6. package/dist/commands/pkg/browse/actions.d.ts +7 -0
  7. package/dist/commands/pkg/browse/actions.js +199 -0
  8. package/dist/commands/pkg/browse/catalog.d.ts +9 -0
  9. package/dist/commands/pkg/browse/catalog.js +466 -0
  10. package/dist/commands/pkg/browse/command-view.d.ts +3 -0
  11. package/dist/commands/pkg/browse/command-view.js +191 -0
  12. package/dist/commands/pkg/browse/detail-panel.d.ts +66 -0
  13. package/dist/commands/pkg/browse/detail-panel.js +402 -0
  14. package/dist/commands/pkg/browse/doc-view.d.ts +3 -0
  15. package/dist/commands/pkg/browse/doc-view.js +81 -0
  16. package/dist/commands/pkg/browse/list-panel.d.ts +28 -0
  17. package/dist/commands/pkg/browse/list-panel.js +168 -0
  18. package/dist/commands/pkg/browse/model.d.ts +230 -0
  19. package/dist/commands/pkg/browse/model.js +36 -0
  20. package/dist/commands/pkg/browse/shell.d.ts +93 -0
  21. package/dist/commands/pkg/browse/shell.js +640 -0
  22. package/dist/commands/pkg/browse.d.ts +2 -0
  23. package/dist/commands/pkg/browse.js +27 -0
  24. package/dist/commands/pkg/market-manage.js +13 -4
  25. package/dist/commands/pkg/plugin-manage.js +8 -3
  26. package/dist/commands/pkg.js +2 -1
  27. package/dist/commands/sys/doctor.js +6 -4
  28. package/dist/commands/sys/panels/broker-limits-panel.d.ts +1 -1
  29. package/dist/commands/sys/panels/broker-limits-panel.js +1 -1
  30. package/dist/commands/sys/panels/dependencies-panel.d.ts +1 -1
  31. package/dist/commands/sys/panels/dependencies-panel.js +1 -1
  32. package/dist/commands/sys/panels/keybindings-panel.js +1 -1
  33. package/dist/commands/sys/panels/models-panel.d.ts +1 -1
  34. package/dist/commands/sys/panels/models-panel.js +1 -1
  35. package/dist/commands/sys/panels/plugins-panel.d.ts +1 -1
  36. package/dist/commands/sys/panels/plugins-panel.js +1 -1
  37. package/dist/commands/sys/panels/prefs-panel.d.ts +1 -1
  38. package/dist/commands/sys/panels/prefs-panel.js +1 -1
  39. package/dist/commands/sys/panels/provider-panel.d.ts +1 -1
  40. package/dist/commands/sys/panels/provider-panel.js +1 -1
  41. package/dist/commands/sys/settings-shell.js +1 -1
  42. package/dist/commands/sys/setup-settings-runner.d.ts +7 -18
  43. package/dist/commands/sys/setup-settings-runner.js +3 -52
  44. package/dist/commands/sys/setup-wizard.js +1 -1
  45. package/dist/core/__tests__/serial/command-plugins.test.js +21 -40
  46. package/dist/core/canvas/nav-model.d.ts +1 -8
  47. package/dist/core/canvas/nav-model.js +30 -59
  48. package/dist/core/canvas/nav-render.d.ts +2 -2
  49. package/dist/core/canvas/nav-render.js +8 -6
  50. package/dist/core/command-manifests/registry.d.ts +10 -3
  51. package/dist/core/command-manifests/registry.js +36 -22
  52. package/dist/core/command-plugins/compose.js +1 -1
  53. package/dist/core/command-plugins/discovery.js +15 -7
  54. package/dist/core/keybindings/catalog.d.ts +1 -1
  55. package/dist/core/keybindings/catalog.js +1 -0
  56. package/dist/core/resolver.d.ts +2 -2
  57. package/dist/core/runtime/tmux-bindings.js +2 -0
  58. package/dist/core/tui/page-host.d.ts +25 -0
  59. package/dist/core/tui/page-host.js +65 -0
  60. package/dist/daemon/__tests__/subtree-filter-freshness.test.d.ts +1 -0
  61. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +63 -0
  62. package/dist/pi-extensions/canvas-bash-valve.js +45 -1
  63. package/dist/types.d.ts +4 -1
  64. package/package.json +1 -1
  65. package/runtime.lock.json +2 -2
  66. /package/dist/{commands/sys/panels → core/tui}/panel.d.ts +0 -0
  67. /package/dist/{commands/sys/panels → core/tui}/panel.js +0 -0
@@ -0,0 +1,7 @@
1
+ import type { ActionPresentation, ActionRequest, ActionOutcome } from "./model.js";
2
+ /** How an action reads before it runs — and whether it needs confirming. */
3
+ export declare function presentAction(request: ActionRequest): ActionPresentation;
4
+ /** Actions available for a request's subject right now, in offer order. */
5
+ export declare function availableActions(request: Pick<ActionRequest, "entry" | "marketplace" | "scope">): ActionRequest[];
6
+ /** Run one action. Never throws: a failure comes back as `ok: false`. */
7
+ export declare function runAction(request: ActionRequest): Promise<ActionOutcome>;
@@ -0,0 +1,199 @@
1
+ // Mutations for `crtr pkg browse`. Each action delegates to the same leaf the
2
+ // CLI runs, so the browser and `crtr pkg …` can never drift.
3
+ import { marketAdd, marketRemove, marketUpdate } from "../market-manage.js";
4
+ import { pluginDisable, pluginEnable, pluginInstall, pluginRemove, pluginUpdate, } from "../plugin-manage.js";
5
+ import { listAllMarketplaces } from "../../../core/resolver.js";
6
+ import { projectScopeRoot } from "../../../core/scope.js";
7
+ function pluginName(request) {
8
+ return request.entry?.name ?? "plugin";
9
+ }
10
+ function marketplaceName(request) {
11
+ return request.marketplace ?? "marketplace";
12
+ }
13
+ /** How an action reads before it runs — and whether it needs confirming. */
14
+ export function presentAction(request) {
15
+ switch (request.kind) {
16
+ case "install": {
17
+ const scope = request.scope ?? "user";
18
+ return { label: `Install into ${scope} scope`, progress: `Installing ${pluginName(request)}…` };
19
+ }
20
+ case "remove":
21
+ return {
22
+ label: `Remove ${pluginName(request)}`,
23
+ progress: `Removing ${pluginName(request)}…`,
24
+ confirm: `Remove ${pluginName(request)} and delete its files?`,
25
+ };
26
+ case "enable":
27
+ return { label: `Enable ${pluginName(request)}`, progress: `Enabling ${pluginName(request)}…` };
28
+ case "disable":
29
+ return { label: `Disable ${pluginName(request)}`, progress: `Disabling ${pluginName(request)}…` };
30
+ case "update":
31
+ return { label: `Update ${pluginName(request)}`, progress: `Updating ${pluginName(request)}…` };
32
+ case "market-add":
33
+ return {
34
+ label: "Add marketplace",
35
+ progress: `Adding ${request.url ?? "marketplace"}…`,
36
+ };
37
+ case "market-update":
38
+ return { label: `Update ${marketplaceName(request)}`, progress: `Updating ${marketplaceName(request)}…` };
39
+ case "market-remove":
40
+ return {
41
+ label: `Remove ${marketplaceName(request)}`,
42
+ progress: `Removing ${marketplaceName(request)}…`,
43
+ confirm: `Remove ${marketplaceName(request)} and its sourced plugins?`,
44
+ };
45
+ }
46
+ return { label: "Run action", progress: "Running action…" };
47
+ }
48
+ /** Actions available for a request's subject right now, in offer order. */
49
+ export function availableActions(request) {
50
+ if (request.entry !== undefined) {
51
+ const { entry } = request;
52
+ if (entry.install.kind === "absent") {
53
+ return [
54
+ { kind: "install", entry, scope: "user" },
55
+ ...(projectScopeRoot() === null ? [] : [{ kind: "install", entry, scope: "project" }]),
56
+ ];
57
+ }
58
+ const actions = [
59
+ { kind: entry.install.enabled ? "disable" : "enable", entry },
60
+ ];
61
+ if (entry.install.scope !== "builtin")
62
+ actions.push({ kind: "remove", entry });
63
+ if (entry.install.updateAvailable)
64
+ actions.push({ kind: "update", entry });
65
+ return actions;
66
+ }
67
+ if (request.marketplace !== undefined) {
68
+ const matching = marketplacesNamed(request.marketplace);
69
+ const scope = matching.length === 1 ? matching[0].scope : request.scope;
70
+ return [
71
+ ...(scope === undefined ? [] : [{ kind: "market-update", marketplace: request.marketplace, scope }]),
72
+ ...(scope === undefined ? [] : [{ kind: "market-remove", marketplace: request.marketplace, scope }]),
73
+ ];
74
+ }
75
+ return [];
76
+ }
77
+ function marketplacesNamed(name) {
78
+ try {
79
+ return listAllMarketplaces().filter((marketplace) => marketplace.name === name);
80
+ }
81
+ catch {
82
+ return [];
83
+ }
84
+ }
85
+ function asRecord(value) {
86
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
87
+ }
88
+ function strings(value) {
89
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
90
+ }
91
+ function commandDetail(value) {
92
+ const commands = asRecord(value);
93
+ const mounts = strings(commands["mounts"]);
94
+ const issues = Array.isArray(commands["issues"]) ? commands["issues"] : [];
95
+ return [
96
+ ...mounts.map((mount) => `Mounted: crtr ${mount}`),
97
+ ...issues.map((issue) => {
98
+ const detail = asRecord(issue);
99
+ const message = detail["message"];
100
+ return `Command issue: ${typeof message === "string" ? message : "invalid command manifest"}`;
101
+ }),
102
+ ];
103
+ }
104
+ function updateDetail(value, noun) {
105
+ const updated = Array.isArray(asRecord(value)["updated"]) ? asRecord(value)["updated"] : [];
106
+ return updated.flatMap((item) => {
107
+ const result = asRecord(item);
108
+ const name = typeof result["name"] === "string" ? result["name"] : noun.toLowerCase();
109
+ const sha = typeof result["sha"] === "string" && result["sha"] !== "" ? ` at ${result["sha"].slice(0, 12)}` : "";
110
+ const state = result["updated"] === true ? `${noun} ${name} updated${sha}.` : `${noun} ${name} is already current${sha}.`;
111
+ return [state, ...commandDetail(result["commands"]), ...(typeof result["error"] === "string" ? [`${noun} ${name}: ${result["error"]}`] : [])];
112
+ });
113
+ }
114
+ function missing(message) {
115
+ return { ok: false, message };
116
+ }
117
+ /** Run one action. Never throws: a failure comes back as `ok: false`. */
118
+ export async function runAction(request) {
119
+ try {
120
+ switch (request.kind) {
121
+ case "install": {
122
+ if (request.entry === undefined)
123
+ return missing("Choose a plugin to install.");
124
+ if (request.scope === undefined)
125
+ return missing("Choose an install scope.");
126
+ if (request.entry.marketplace !== undefined && marketplacesNamed(request.entry.marketplace).length > 1) {
127
+ return missing(`Cannot safely install ${request.entry.name}: marketplace "${request.entry.marketplace}" exists in more than one scope.`);
128
+ }
129
+ const result = await pluginInstall.run({ installRef: request.entry.ref, scope: request.scope });
130
+ const installed = asRecord(result);
131
+ const name = typeof installed["name"] === "string" ? installed["name"] : request.entry.name;
132
+ const scope = typeof installed["scope"] === "string" ? installed["scope"] : request.scope;
133
+ return { ok: true, message: `Installed ${name} in ${scope} scope.`, detail: commandDetail(installed["commands"]) };
134
+ }
135
+ case "remove": {
136
+ if (request.entry === undefined || request.entry.install.kind !== "installed")
137
+ return missing("Choose an installed plugin to remove.");
138
+ const result = asRecord(await pluginRemove.run({ name: request.entry.name, scope: request.entry.install.scope }));
139
+ const scopes = strings(result["scopes"]);
140
+ return { ok: true, message: `Removed ${request.entry.name}${scopes.length > 0 ? ` from ${scopes.join(", ")} scope${scopes.length === 1 ? "" : "s"}` : ""}.` };
141
+ }
142
+ case "enable": {
143
+ if (request.entry === undefined || request.entry.install.kind !== "installed")
144
+ return missing("Choose an installed plugin to enable.");
145
+ const result = asRecord(await pluginEnable.run({ name: request.entry.name, scope: request.entry.install.scope }));
146
+ const scope = typeof result["scope"] === "string" ? result["scope"] : request.entry.install.scope;
147
+ return { ok: true, message: `Enabled ${request.entry.name} in ${scope} scope.` };
148
+ }
149
+ case "disable": {
150
+ if (request.entry === undefined || request.entry.install.kind !== "installed")
151
+ return missing("Choose an installed plugin to disable.");
152
+ const result = asRecord(await pluginDisable.run({ name: request.entry.name, scope: request.entry.install.scope }));
153
+ const scope = typeof result["scope"] === "string" ? result["scope"] : request.entry.install.scope;
154
+ return { ok: true, message: `Disabled ${request.entry.name} in ${scope} scope.` };
155
+ }
156
+ case "update": {
157
+ if (request.entry === undefined || request.entry.install.kind !== "installed")
158
+ return missing("Choose an installed plugin to update.");
159
+ const result = await pluginUpdate.run({ name: request.entry.name, scope: request.entry.install.scope });
160
+ const detail = updateDetail(result, "Plugin");
161
+ return { ok: true, message: detail[0] ?? `Updated ${request.entry.name}.`, detail };
162
+ }
163
+ case "market-add": {
164
+ if (request.url === undefined || request.url === "")
165
+ return missing("Enter a marketplace git URL.");
166
+ const result = asRecord(await marketAdd.run({
167
+ url: request.url,
168
+ ...(request.ref !== undefined ? { ref: request.ref } : {}),
169
+ ...(request.scope !== undefined ? { scope: request.scope } : {}),
170
+ }));
171
+ const name = typeof result["name"] === "string" ? result["name"] : request.url;
172
+ const scope = typeof result["scope"] === "string" ? result["scope"] : request.scope;
173
+ return { ok: true, message: `Added marketplace ${name}${scope === undefined ? "" : ` in ${scope} scope`}.` };
174
+ }
175
+ case "market-update": {
176
+ if (request.marketplace === undefined)
177
+ return missing("Choose a marketplace to update.");
178
+ if (request.scope === undefined)
179
+ return missing("Choose a marketplace scope to update.");
180
+ const result = await marketUpdate.run({ name: request.marketplace, scope: request.scope });
181
+ const detail = updateDetail(result, "Marketplace");
182
+ return { ok: true, message: detail[0] ?? `Updated ${request.marketplace}.`, detail };
183
+ }
184
+ case "market-remove": {
185
+ if (request.marketplace === undefined)
186
+ return missing("Choose a marketplace to remove.");
187
+ if (request.scope === undefined)
188
+ return missing("Choose a marketplace scope to remove.");
189
+ const result = asRecord(await marketRemove.run({ name: request.marketplace, scope: request.scope }));
190
+ const name = typeof result["name"] === "string" ? result["name"] : request.marketplace;
191
+ return { ok: true, message: `Removed marketplace ${name}.` };
192
+ }
193
+ }
194
+ return missing("Unsupported action.");
195
+ }
196
+ catch (error) {
197
+ return { ok: false, message: error instanceof Error ? error.message : String(error) };
198
+ }
199
+ }
@@ -0,0 +1,9 @@
1
+ import { type Catalog, type PluginCapability, type PluginEntry } from "./model.js";
2
+ /** Every rail source with its rows: the installed library first, then each
3
+ * registered marketplace. Called on open and after any action that could
4
+ * change install state. Must never throw for a broken marketplace — record it
5
+ * in `warnings` and keep the rest of the catalog. */
6
+ export declare function loadCatalog(): Catalog;
7
+ /** What the focused plugin adds to this machine. Resolved from `entry.root`;
8
+ * null when the plugin has no directory on disk yet. */
9
+ export declare function loadCapability(entry: PluginEntry): Promise<PluginCapability | null>;