@skilly-hand/skilly-hand 0.23.0 → 0.23.2
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 +35 -0
- package/README.md +3 -2
- package/package.json +4 -4
- package/packages/catalog/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/bin.js +19 -24
- package/packages/cli/src/command-registry.js +108 -0
- package/packages/cli/src/inquirer-ui.js +201 -0
- package/packages/core/package.json +1 -1
- package/packages/detectors/package.json +1 -1
- package/packages/cli/src/ink-ui.js +0 -969
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,41 @@ All notable changes to this project are documented in this file.
|
|
|
16
16
|
### Removed
|
|
17
17
|
- _None._
|
|
18
18
|
|
|
19
|
+
## [0.23.2] - 2026-04-13
|
|
20
|
+
[View on npm](https://www.npmjs.com/package/@skilly-hand/skilly-hand/v/0.23.2)
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- Added regression coverage in interactive CLI tests to assert the explicit next-action prompt copy shown after install confirmation.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- Updated the interactive install decision prompt text to make `apply` and `menu` actions explicit for guided launcher users.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- _None._
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
- _None._
|
|
33
|
+
|
|
34
|
+
## [0.23.1] - 2026-04-13
|
|
35
|
+
[View on npm](https://www.npmjs.com/package/@skilly-hand/skilly-hand/v/0.23.1)
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
- Added an Inquirer-powered guided home launcher with searchable command discovery and a built-in Command Guide.
|
|
39
|
+
- Added shared CLI command metadata in `packages/cli/src/command-registry.js` and wired help/interactive flows to consume it.
|
|
40
|
+
- Added `scripts/review-rangers-check.mjs` plus `npm run review:rangers`, and integrated it into `verify:publish`.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- Updated CLI help output to include a dedicated Commands section sourced from the shared command registry.
|
|
44
|
+
- Updated docs to describe the new interactive launcher and mark `--classic` as a deprecated compatibility flag.
|
|
45
|
+
- Updated dependency policy and script contract tests for the new release gates and runtime dependency set.
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
- Added guard tests to prevent reintroducing `react`/`ink` runtime dependencies after the interactive stack migration.
|
|
49
|
+
|
|
50
|
+
### Removed
|
|
51
|
+
- Removed the legacy Ink full-screen UI implementation (`packages/cli/src/ink-ui.js`) and related tests.
|
|
52
|
+
- Removed runtime dependencies on `ink` and `react` in favor of `inquirer`.
|
|
53
|
+
|
|
19
54
|
## [0.23.0] - 2026-04-12
|
|
20
55
|
[View on npm](https://www.npmjs.com/package/@skilly-hand/skilly-hand/v/0.23.0)
|
|
21
56
|
|
package/README.md
CHANGED
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
npx skilly-hand
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
`npx skilly-hand` opens
|
|
39
|
+
`npx skilly-hand` opens an interactive prompt workflow when running in a TTY.
|
|
40
|
+
The guided home supports type-to-filter command discovery and includes a built-in Command Guide.
|
|
40
41
|
|
|
41
42
|
---
|
|
42
43
|
|
|
@@ -55,7 +56,7 @@ npx skilly-hand
|
|
|
55
56
|
| Flag | Description |
|
|
56
57
|
| ---- | ----------- |
|
|
57
58
|
| `--json` | Emit machine-readable output and disable interactive prompts |
|
|
58
|
-
| `--classic` |
|
|
59
|
+
| `--classic` | Deprecated compatibility flag that keeps plain command mode (launcher disabled) |
|
|
59
60
|
| `--yes`, `-y` | Skip confirmation prompts for mutating commands (`install`, `uninstall`) |
|
|
60
61
|
| `--dry-run` | Preview install plan without writing files |
|
|
61
62
|
| `--agent`, `-a <name>` | Target a specific assistant (repeatable; e.g. `--agent claude --agent cursor`) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skilly-hand/skilly-hand",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.2",
|
|
4
4
|
"license": "CC-BY-NC-4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
"security:check": "node ./scripts/security-check.mjs --strict-deps",
|
|
36
36
|
"verify:packlist": "node ./scripts/verify-packlist.mjs",
|
|
37
37
|
"verify:versions": "node ./scripts/verify-versions.mjs",
|
|
38
|
-
"
|
|
38
|
+
"review:rangers": "node ./scripts/review-rangers-check.mjs",
|
|
39
|
+
"verify:publish": "npm run verify:versions && npm run deps:policy:check && npm run security:check && npm run catalog:check && npm test && npm run review:rangers && npm run verify:packlist",
|
|
39
40
|
"publish:prepare": "npm run verify:publish && npm pack --dry-run --json",
|
|
40
41
|
"publish:otp": "node ./scripts/publish-with-otp.mjs",
|
|
41
42
|
"publish:next": "node ./scripts/publish-with-otp.mjs --tag next",
|
|
@@ -49,7 +50,6 @@
|
|
|
49
50
|
"doctor": "node ./packages/cli/src/bin.js doctor"
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {
|
|
52
|
-
"
|
|
53
|
-
"react": "19.2.5"
|
|
53
|
+
"inquirer": "13.4.1"
|
|
54
54
|
}
|
|
55
55
|
}
|
package/packages/cli/src/bin.js
CHANGED
|
@@ -14,7 +14,8 @@ import {
|
|
|
14
14
|
} from "../../core/src/index.js";
|
|
15
15
|
import { createTerminalRenderer } from "../../core/src/terminal.js";
|
|
16
16
|
import { detectProject } from "../../detectors/src/index.js";
|
|
17
|
-
import {
|
|
17
|
+
import { createInquirerInteractiveUi } from "./inquirer-ui.js";
|
|
18
|
+
import { formatHelpUsageLines, getCliCommands, getInteractiveCommands } from "./command-registry.js";
|
|
18
19
|
import {
|
|
19
20
|
createResultDoc,
|
|
20
21
|
kvBlock,
|
|
@@ -90,20 +91,17 @@ export function parseArgs(argv) {
|
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
function buildHelpText(renderer, appVersion) {
|
|
93
|
-
const usage = renderer.section("Usage", renderer.list(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
"
|
|
98
|
-
|
|
99
|
-
"npx skilly-hand doctor",
|
|
100
|
-
"npx skilly-hand uninstall"
|
|
101
|
-
], { bullet: "-" }));
|
|
94
|
+
const usage = renderer.section("Usage", renderer.list(formatHelpUsageLines(), { bullet: "-" }));
|
|
95
|
+
|
|
96
|
+
const commands = renderer.section("Commands", renderer.list(
|
|
97
|
+
getCliCommands().map((command) => `${command.usage} # ${command.description}`),
|
|
98
|
+
{ bullet: "-" }
|
|
99
|
+
));
|
|
102
100
|
|
|
103
101
|
const flags = renderer.section("Flags", renderer.list([
|
|
104
102
|
"--dry-run Show install plan without writing files",
|
|
105
103
|
"--json Emit stable JSON output for automation",
|
|
106
|
-
"--classic
|
|
104
|
+
"--classic Deprecated alias for plain command mode (launcher disabled)",
|
|
107
105
|
"--yes, -y Skip install/uninstall confirmations",
|
|
108
106
|
"--verbose, -v Reserved for future debug detail",
|
|
109
107
|
"--agent, -a <name> standard|codex|claude|cursor|gemini|copilot|antigravity|windsurf|trae (repeatable)",
|
|
@@ -125,6 +123,7 @@ function buildHelpText(renderer, appVersion) {
|
|
|
125
123
|
return renderer.joinBlocks([
|
|
126
124
|
renderer.banner(appVersion),
|
|
127
125
|
usage,
|
|
126
|
+
commands,
|
|
128
127
|
flags,
|
|
129
128
|
examples
|
|
130
129
|
]);
|
|
@@ -474,8 +473,11 @@ async function runInteractiveSession({
|
|
|
474
473
|
appVersion,
|
|
475
474
|
interactiveUi
|
|
476
475
|
}) {
|
|
476
|
+
const interactiveCommands = getInteractiveCommands();
|
|
477
|
+
|
|
477
478
|
await interactiveUi.launch({
|
|
478
479
|
appVersion,
|
|
480
|
+
commands: interactiveCommands,
|
|
479
481
|
actions: {
|
|
480
482
|
async runCommandBundle(command) {
|
|
481
483
|
if (command === "native-setup") {
|
|
@@ -738,10 +740,7 @@ export async function runCli({
|
|
|
738
740
|
env = process.env,
|
|
739
741
|
platform = process.platform,
|
|
740
742
|
services: providedServices = {},
|
|
741
|
-
interactiveUi =
|
|
742
|
-
launch: ({ appVersion, actions }) => launchInkApp({ appVersion, actions }),
|
|
743
|
-
confirm: ({ message, defaultValue }) => confirmWithInk({ message, defaultValue })
|
|
744
|
-
},
|
|
743
|
+
interactiveUi = createInquirerInteractiveUi(),
|
|
745
744
|
appVersion = version,
|
|
746
745
|
cwdResolver = process.cwd
|
|
747
746
|
} = {}) {
|
|
@@ -754,15 +753,7 @@ export async function runCli({
|
|
|
754
753
|
renderer.writeJson({
|
|
755
754
|
command: command || "install",
|
|
756
755
|
help: true,
|
|
757
|
-
usage: [
|
|
758
|
-
"npx skilly-hand",
|
|
759
|
-
"npx skilly-hand install",
|
|
760
|
-
"npx skilly-hand native setup",
|
|
761
|
-
"npx skilly-hand detect",
|
|
762
|
-
"npx skilly-hand list",
|
|
763
|
-
"npx skilly-hand doctor",
|
|
764
|
-
"npx skilly-hand uninstall"
|
|
765
|
-
]
|
|
756
|
+
usage: formatHelpUsageLines().map((line) => line.split("#")[0].trim())
|
|
766
757
|
});
|
|
767
758
|
return;
|
|
768
759
|
}
|
|
@@ -773,6 +764,10 @@ export async function runCli({
|
|
|
773
764
|
|
|
774
765
|
const cwd = path.resolve(flags.cwd || cwdResolver());
|
|
775
766
|
|
|
767
|
+
if (flags.classic && !flags.json) {
|
|
768
|
+
renderer.write(renderer.status("info", "`--classic` is deprecated and kept only for backwards compatibility."));
|
|
769
|
+
}
|
|
770
|
+
|
|
776
771
|
if (isInteractiveLauncherMode({ command, flags, stdout, stdin })) {
|
|
777
772
|
try {
|
|
778
773
|
await runInteractiveSession({
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const CLI_COMMANDS = [
|
|
2
|
+
{
|
|
3
|
+
value: "install",
|
|
4
|
+
label: "Install",
|
|
5
|
+
description: "Install portable skills into the current project.",
|
|
6
|
+
bestFor: "First-time setup and skill refresh",
|
|
7
|
+
aliases: ["setup", "init", "apply"],
|
|
8
|
+
usage: "npx skilly-hand install"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
value: "native-setup",
|
|
12
|
+
label: "Native Setup",
|
|
13
|
+
description: "Sync native assistant adapters and instruction files.",
|
|
14
|
+
bestFor: "After install or when assistant targets change",
|
|
15
|
+
aliases: ["native", "adapters"],
|
|
16
|
+
usage: "npx skilly-hand native setup"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
value: "detect",
|
|
20
|
+
label: "Detect",
|
|
21
|
+
description: "Scan project technologies and show detected signals.",
|
|
22
|
+
bestFor: "Preview auto-detection before installation",
|
|
23
|
+
aliases: ["scan", "inspect"],
|
|
24
|
+
usage: "npx skilly-hand detect"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
value: "list",
|
|
28
|
+
label: "List",
|
|
29
|
+
description: "List all skills available in the catalog.",
|
|
30
|
+
bestFor: "Browse skills and tags",
|
|
31
|
+
aliases: ["catalog", "skills"],
|
|
32
|
+
usage: "npx skilly-hand list"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
value: "doctor",
|
|
36
|
+
label: "Doctor",
|
|
37
|
+
description: "Diagnose install health, probes, and native coverage.",
|
|
38
|
+
bestFor: "Troubleshooting and pre-release checks",
|
|
39
|
+
aliases: ["health", "check"],
|
|
40
|
+
usage: "npx skilly-hand doctor"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: "uninstall",
|
|
44
|
+
label: "Uninstall",
|
|
45
|
+
description: "Remove managed skilly-hand installation files.",
|
|
46
|
+
bestFor: "Restore project to pre-install state",
|
|
47
|
+
aliases: ["remove", "cleanup"],
|
|
48
|
+
usage: "npx skilly-hand uninstall"
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const INTERACTIVE_ONLY_COMMANDS = [
|
|
53
|
+
{
|
|
54
|
+
value: "command-guide",
|
|
55
|
+
label: "Command Guide",
|
|
56
|
+
description: "Show command explanations, aliases, and examples.",
|
|
57
|
+
bestFor: "Learning what to run",
|
|
58
|
+
aliases: ["help", "guide"],
|
|
59
|
+
usage: "npx skilly-hand --help"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
value: "exit",
|
|
63
|
+
label: "Exit",
|
|
64
|
+
description: "Close the guided launcher.",
|
|
65
|
+
bestFor: "Leave interactive mode",
|
|
66
|
+
aliases: ["quit"],
|
|
67
|
+
usage: "npx skilly-hand"
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
function normalizeText(value) {
|
|
72
|
+
return String(value || "").trim().toLowerCase();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function buildSearchText(command) {
|
|
76
|
+
return [
|
|
77
|
+
command.value,
|
|
78
|
+
command.label,
|
|
79
|
+
command.description,
|
|
80
|
+
command.bestFor,
|
|
81
|
+
...(command.aliases || [])
|
|
82
|
+
]
|
|
83
|
+
.map(normalizeText)
|
|
84
|
+
.join(" ");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function getCliCommands() {
|
|
88
|
+
return CLI_COMMANDS.map((command) => ({ ...command, aliases: [...command.aliases] }));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getInteractiveCommands() {
|
|
92
|
+
const merged = [...CLI_COMMANDS, ...INTERACTIVE_ONLY_COMMANDS];
|
|
93
|
+
return merged.map((command) => ({ ...command, aliases: [...command.aliases] }));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function filterCommands(commands, term) {
|
|
97
|
+
const normalizedTerm = normalizeText(term);
|
|
98
|
+
if (!normalizedTerm) return [...commands];
|
|
99
|
+
return commands.filter((command) => buildSearchText(command).includes(normalizedTerm));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function formatHelpUsageLines() {
|
|
103
|
+
return [
|
|
104
|
+
"npx skilly-hand # interactive launcher when running in a TTY",
|
|
105
|
+
...CLI_COMMANDS.map((command) => command.usage)
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import { filterCommands, getInteractiveCommands } from "./command-registry.js";
|
|
3
|
+
|
|
4
|
+
function writeBlock(write, title, body) {
|
|
5
|
+
const lines = [];
|
|
6
|
+
if (title) {
|
|
7
|
+
lines.push(`\n${title}`);
|
|
8
|
+
lines.push("=".repeat(Math.max(12, title.length)));
|
|
9
|
+
}
|
|
10
|
+
if (body) {
|
|
11
|
+
lines.push(String(body).trimEnd());
|
|
12
|
+
}
|
|
13
|
+
lines.push("");
|
|
14
|
+
write(`${lines.join("\n")}\n`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function formatSkillChoiceLabel(skill) {
|
|
18
|
+
const tags = (skill.tags || []).join(", ") || "none";
|
|
19
|
+
const agents = (skill.agentSupport || []).join(", ") || "none";
|
|
20
|
+
return `${skill.id} | ${skill.title} | tags: ${tags} | agents: ${agents}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function toCheckboxChoices(items, valueKey, labelFn) {
|
|
24
|
+
return items.map((item) => ({
|
|
25
|
+
name: labelFn(item),
|
|
26
|
+
value: item[valueKey],
|
|
27
|
+
checked: Boolean(item.checked)
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function commandChoiceName(command) {
|
|
32
|
+
return `${command.label} - ${command.description}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function buildCommandGuide(commands) {
|
|
36
|
+
const rows = commands.filter((command) => command.value !== "exit").map((command) => {
|
|
37
|
+
const aliases = (command.aliases || []).join(", ") || "none";
|
|
38
|
+
return [
|
|
39
|
+
`${command.label} (${command.value})`,
|
|
40
|
+
`Best for: ${command.bestFor}`,
|
|
41
|
+
`Aliases: ${aliases}`,
|
|
42
|
+
`Run: ${command.usage}`
|
|
43
|
+
].join("\n");
|
|
44
|
+
});
|
|
45
|
+
return rows.join("\n\n");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function buildGuidedHomeIntro() {
|
|
49
|
+
return [
|
|
50
|
+
"Type to filter commands, then press Enter to run.",
|
|
51
|
+
"Tips: arrow keys to navigate, Esc to clear search, Ctrl+C to exit."
|
|
52
|
+
].join("\n");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function installTipsBlock() {
|
|
56
|
+
return [
|
|
57
|
+
"Recommended skills are preselected using stack detection.",
|
|
58
|
+
"Use space to toggle, a to toggle all, i to invert selection."
|
|
59
|
+
].join("\n");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function agentTipsBlock() {
|
|
63
|
+
return [
|
|
64
|
+
"Pick assistant targets that should receive installed skills.",
|
|
65
|
+
"Use space to toggle and Enter to continue."
|
|
66
|
+
].join("\n");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const COMMAND_HINTS = {
|
|
70
|
+
"native-setup": "Tip: run `npx skilly-hand doctor` next to verify native coverage.",
|
|
71
|
+
detect: "Tip: run `npx skilly-hand install` to apply detected recommendations.",
|
|
72
|
+
list: "Tip: use `npx skilly-hand install --include <tag>` to narrow installation.",
|
|
73
|
+
doctor: "Tip: resolve any warnings, then rerun doctor before release.",
|
|
74
|
+
uninstall: "Tip: run `npx skilly-hand install` anytime to restore managed files."
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export function createInquirerInteractiveUi({
|
|
78
|
+
prompt = (questions) => inquirer.prompt(questions),
|
|
79
|
+
write = (value) => process.stdout.write(value)
|
|
80
|
+
} = {}) {
|
|
81
|
+
async function confirm({ message, defaultValue = false }) {
|
|
82
|
+
try {
|
|
83
|
+
const response = await prompt([
|
|
84
|
+
{
|
|
85
|
+
type: "confirm",
|
|
86
|
+
name: "confirmed",
|
|
87
|
+
message: String(message),
|
|
88
|
+
default: defaultValue
|
|
89
|
+
}
|
|
90
|
+
]);
|
|
91
|
+
return Boolean(response.confirmed);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error?.name === "ExitPromptError") return false;
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function launch({ appVersion, actions, commands = getInteractiveCommands() }) {
|
|
99
|
+
const header = appVersion ? `skilly-hand v${appVersion}` : "skilly-hand";
|
|
100
|
+
writeBlock(write, "Guided Home", buildGuidedHomeIntro());
|
|
101
|
+
|
|
102
|
+
while (true) {
|
|
103
|
+
const { command } = await prompt([
|
|
104
|
+
{
|
|
105
|
+
type: "search",
|
|
106
|
+
name: "command",
|
|
107
|
+
message: `${header}: choose a command`,
|
|
108
|
+
source: async (term) =>
|
|
109
|
+
filterCommands(commands, term).map((item) => ({
|
|
110
|
+
name: commandChoiceName(item),
|
|
111
|
+
value: item.value,
|
|
112
|
+
description: `${item.bestFor} | aliases: ${(item.aliases || []).join(", ") || "none"}`
|
|
113
|
+
})),
|
|
114
|
+
default: "install",
|
|
115
|
+
pageSize: 10
|
|
116
|
+
}
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
if (command === "exit") return;
|
|
120
|
+
if (command === "command-guide") {
|
|
121
|
+
writeBlock(write, "Command Guide", buildCommandGuide(commands));
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (command === "install") {
|
|
126
|
+
const context = await actions.prepareInstall();
|
|
127
|
+
const skillChoices = toCheckboxChoices(context.skills || [], "id", formatSkillChoiceLabel);
|
|
128
|
+
const agentChoices = toCheckboxChoices(context.agents || [], "value", (agent) => agent.value);
|
|
129
|
+
|
|
130
|
+
writeBlock(write, "Install Tips", installTipsBlock());
|
|
131
|
+
|
|
132
|
+
const { selectedSkillIds } = await prompt([
|
|
133
|
+
{
|
|
134
|
+
type: "checkbox",
|
|
135
|
+
name: "selectedSkillIds",
|
|
136
|
+
message: "Select skills to install",
|
|
137
|
+
choices: skillChoices,
|
|
138
|
+
pageSize: 16
|
|
139
|
+
}
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
writeBlock(write, "Assistant Target Tips", agentTipsBlock());
|
|
143
|
+
|
|
144
|
+
const { selectedAgents } = await prompt([
|
|
145
|
+
{
|
|
146
|
+
type: "checkbox",
|
|
147
|
+
name: "selectedAgents",
|
|
148
|
+
message: "Select assistant targets",
|
|
149
|
+
choices: agentChoices,
|
|
150
|
+
pageSize: 12
|
|
151
|
+
}
|
|
152
|
+
]);
|
|
153
|
+
|
|
154
|
+
const previewBundle = await actions.previewInstallBundle({
|
|
155
|
+
selectedSkillIds,
|
|
156
|
+
selectedAgents
|
|
157
|
+
});
|
|
158
|
+
writeBlock(write, "Install Preview", previewBundle?.text || "");
|
|
159
|
+
|
|
160
|
+
const { installDecision } = await prompt([
|
|
161
|
+
{
|
|
162
|
+
type: "list",
|
|
163
|
+
name: "installDecision",
|
|
164
|
+
message: "Next action (type 'apply' to install, or 'menu' to go back)",
|
|
165
|
+
choices: [
|
|
166
|
+
{ name: "Apply installation", value: "apply" },
|
|
167
|
+
{ name: "Back to command menu", value: "menu" }
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
if (installDecision === "apply") {
|
|
173
|
+
const applyBundle = await actions.applyInstallBundle({
|
|
174
|
+
selectedSkillIds,
|
|
175
|
+
selectedAgents
|
|
176
|
+
});
|
|
177
|
+
writeBlock(write, "Install Result", applyBundle?.text || "");
|
|
178
|
+
writeBlock(write, "Next Hint", "Run `npx skilly-hand doctor` to verify installation health.");
|
|
179
|
+
}
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (command === "uninstall") {
|
|
184
|
+
const accepted = await confirm({
|
|
185
|
+
message: "Remove the skilly-hand installation from this project?",
|
|
186
|
+
defaultValue: false
|
|
187
|
+
});
|
|
188
|
+
if (!accepted) {
|
|
189
|
+
writeBlock(write, "Uninstall", "Uninstall cancelled.");
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const bundle = await actions.runCommandBundle(command);
|
|
195
|
+
writeBlock(write, "Command Result", bundle?.text || "");
|
|
196
|
+
if (COMMAND_HINTS[command]) writeBlock(write, "Next Hint", COMMAND_HINTS[command]);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return { launch, confirm };
|
|
201
|
+
}
|