@xmoon76/dsh-pi-tui 0.1.7 → 0.1.8
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/dist/index.mjs +114 -63
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -29,7 +29,7 @@ import { eastAsianWidth } from "get-east-asian-width";
|
|
|
29
29
|
import { performance } from "node:perf_hooks";
|
|
30
30
|
import { fileURLToPath } from "node:url";
|
|
31
31
|
import { EventEmitter } from "events";
|
|
32
|
-
import { isUserInvocable } from "@deepseek-ai/dsh-skill";
|
|
32
|
+
import { isUserInvocable, renderSkillContent } from "@deepseek-ai/dsh-skill";
|
|
33
33
|
//#region src/present.ts
|
|
34
34
|
/** Figma row titles per variant (design literals, not translatable copy). */
|
|
35
35
|
const VARIANT_TITLES = {
|
|
@@ -12859,10 +12859,10 @@ var TaskBrowserPanel = class {
|
|
|
12859
12859
|
this.searchInput.invalidate();
|
|
12860
12860
|
}
|
|
12861
12861
|
handleInput(data) {
|
|
12862
|
-
const isNavUp = data
|
|
12863
|
-
const isNavDown = data
|
|
12864
|
-
const isPage = data
|
|
12865
|
-
if (!isNavUp && !isNavDown && !isPage && data
|
|
12862
|
+
const isNavUp = matchesKey(data, "up") || !this.searchEnabled && data === "k";
|
|
12863
|
+
const isNavDown = matchesKey(data, "down") || !this.searchEnabled && data === "j";
|
|
12864
|
+
const isPage = matchesKey(data, "pageUp") || matchesKey(data, "pageDown");
|
|
12865
|
+
if (!isNavUp && !isNavDown && !isPage && !matchesKey(data, "enter") && !matchesKey(data, "escape") && this.searchEnabled) {
|
|
12866
12866
|
this.searchInput.handleInput(data);
|
|
12867
12867
|
this.applyFilter(this.searchInput.getValue() ?? "");
|
|
12868
12868
|
return;
|
|
@@ -12881,17 +12881,17 @@ var TaskBrowserPanel = class {
|
|
|
12881
12881
|
}
|
|
12882
12882
|
if (isPage) {
|
|
12883
12883
|
if (this.filtered.length === 0) return;
|
|
12884
|
-
if (data
|
|
12884
|
+
if (matchesKey(data, "pageUp")) this.selected = Math.max(0, this.selected - this.maxVisible);
|
|
12885
12885
|
else this.selected = Math.min(this.filtered.length - 1, this.selected + this.maxVisible);
|
|
12886
12886
|
this.ensureVisible();
|
|
12887
12887
|
return;
|
|
12888
12888
|
}
|
|
12889
|
-
if (data
|
|
12889
|
+
if (matchesKey(data, "enter")) {
|
|
12890
12890
|
const item = this.filtered[this.selected];
|
|
12891
12891
|
if (item !== void 0) this.onSelect(item.value);
|
|
12892
12892
|
return;
|
|
12893
12893
|
}
|
|
12894
|
-
if (data
|
|
12894
|
+
if (matchesKey(data, "escape")) this.onCancel();
|
|
12895
12895
|
}
|
|
12896
12896
|
ensureVisible() {
|
|
12897
12897
|
if (this.selected < this.scroll) this.scroll = this.selected;
|
|
@@ -13493,8 +13493,9 @@ var QuestionFlow = class {
|
|
|
13493
13493
|
if (draft === void 0) return;
|
|
13494
13494
|
const text = value.trim();
|
|
13495
13495
|
draft.custom = text;
|
|
13496
|
-
if (text === "")
|
|
13497
|
-
|
|
13496
|
+
if (text === "") {
|
|
13497
|
+
if (draft.selected.size === 0) draft.skipped = true;
|
|
13498
|
+
} else {
|
|
13498
13499
|
if (this.questions[this.tab]?.multiSelect !== true) draft.selected.clear();
|
|
13499
13500
|
draft.skipped = false;
|
|
13500
13501
|
}
|
|
@@ -13526,44 +13527,34 @@ var QuestionFlow = class {
|
|
|
13526
13527
|
handleInput(data) {
|
|
13527
13528
|
if (data === "\0") return;
|
|
13528
13529
|
if (this.editingOther) {
|
|
13529
|
-
if (data
|
|
13530
|
-
else if (data
|
|
13531
|
-
else if (data
|
|
13532
|
-
else if (data
|
|
13530
|
+
if (matchesKey(data, "enter")) this.commitOther(this.otherInput.getValue());
|
|
13531
|
+
else if (matchesKey(data, "escape")) this.exitOther();
|
|
13532
|
+
else if (matchesKey(data, "pageUp")) this.scrollBody(-1);
|
|
13533
|
+
else if (matchesKey(data, "pageDown")) this.scrollBody(1);
|
|
13534
|
+
else if (matchesKey(data, "left")) {
|
|
13533
13535
|
if (this.tab > 0) {
|
|
13534
13536
|
this.tab -= 1;
|
|
13535
13537
|
this.cursor = 0;
|
|
13536
13538
|
this.submitIdx = 0;
|
|
13537
13539
|
this.syncEditMode();
|
|
13538
13540
|
}
|
|
13539
|
-
} else if (data
|
|
13540
|
-
|
|
13541
|
-
this.tab += 1;
|
|
13542
|
-
this.cursor = 0;
|
|
13543
|
-
this.submitIdx = 0;
|
|
13544
|
-
this.syncEditMode();
|
|
13545
|
-
} else {
|
|
13546
|
-
this.tab = this.questions.length;
|
|
13547
|
-
this.submitIdx = 0;
|
|
13548
|
-
this.syncEditMode();
|
|
13549
|
-
}
|
|
13550
|
-
} else this.otherInput.handleInput(data);
|
|
13541
|
+
} else if (matchesKey(data, "right")) this.commitOther(this.otherInput.getValue());
|
|
13542
|
+
else this.otherInput.handleInput(data);
|
|
13551
13543
|
return;
|
|
13552
13544
|
}
|
|
13553
13545
|
const rows = this.rows();
|
|
13554
13546
|
if (this.tab >= this.questions.length) {
|
|
13555
|
-
if (data
|
|
13547
|
+
if (matchesKey(data, "enter")) {
|
|
13556
13548
|
if (this.submitIdx === 0) this.submit();
|
|
13557
13549
|
else this.onCancel();
|
|
13558
|
-
} else if (data
|
|
13559
|
-
else if (data
|
|
13560
|
-
else if (data === "\x1B[C" || data === "l") this.submitIdx = 1;
|
|
13561
|
-
else if (data === "b") {
|
|
13550
|
+
} else if (matchesKey(data, "escape")) this.onCancel();
|
|
13551
|
+
else if (matchesKey(data, "left") || data === "h") {
|
|
13562
13552
|
this.tab = Math.max(0, this.questions.length - 1);
|
|
13563
13553
|
this.cursor = 0;
|
|
13564
13554
|
this.submitIdx = 0;
|
|
13565
13555
|
this.syncEditMode();
|
|
13566
|
-
}
|
|
13556
|
+
} else if (matchesKey(data, "up") || data === "k") this.submitIdx = 0;
|
|
13557
|
+
else if (matchesKey(data, "down") || data === "j") this.submitIdx = 1;
|
|
13567
13558
|
return;
|
|
13568
13559
|
}
|
|
13569
13560
|
const digit = /^[1-9]$/.exec(data);
|
|
@@ -13576,7 +13567,7 @@ var QuestionFlow = class {
|
|
|
13576
13567
|
}
|
|
13577
13568
|
return;
|
|
13578
13569
|
}
|
|
13579
|
-
if (data
|
|
13570
|
+
if (matchesKey(data, "up") || data === "k") {
|
|
13580
13571
|
if (rows.length === 0) return;
|
|
13581
13572
|
if (this.cursor === 0 && this.bodyScroll > 0) {
|
|
13582
13573
|
this.scrollBody(-1);
|
|
@@ -13586,7 +13577,7 @@ var QuestionFlow = class {
|
|
|
13586
13577
|
this.pendingCursorScroll = true;
|
|
13587
13578
|
return;
|
|
13588
13579
|
}
|
|
13589
|
-
if (data
|
|
13580
|
+
if (matchesKey(data, "down") || data === "j") {
|
|
13590
13581
|
if (rows.length === 0) return;
|
|
13591
13582
|
const atLastRow = this.cursor === rows.length - 1;
|
|
13592
13583
|
const scrolled = this.lastExpandable && this.lastContentRows > this.bodyScroll + this.lastVisibleRows;
|
|
@@ -13598,19 +13589,19 @@ var QuestionFlow = class {
|
|
|
13598
13589
|
this.pendingCursorScroll = true;
|
|
13599
13590
|
return;
|
|
13600
13591
|
}
|
|
13601
|
-
if (data
|
|
13602
|
-
this.scrollBody(data
|
|
13592
|
+
if (matchesKey(data, "pageUp") || matchesKey(data, "pageDown")) {
|
|
13593
|
+
this.scrollBody(matchesKey(data, "pageUp") ? -1 : 1);
|
|
13603
13594
|
return;
|
|
13604
13595
|
}
|
|
13605
13596
|
if (data === "e") {
|
|
13606
13597
|
this.toggleExpanded();
|
|
13607
13598
|
return;
|
|
13608
13599
|
}
|
|
13609
|
-
if (data
|
|
13600
|
+
if (matchesKey(data, "enter")) {
|
|
13610
13601
|
this.confirm();
|
|
13611
13602
|
return;
|
|
13612
13603
|
}
|
|
13613
|
-
if (data
|
|
13604
|
+
if (matchesKey(data, "left") || data === "h") {
|
|
13614
13605
|
if (this.tab > 0) {
|
|
13615
13606
|
this.tab -= 1;
|
|
13616
13607
|
this.cursor = 0;
|
|
@@ -13619,7 +13610,11 @@ var QuestionFlow = class {
|
|
|
13619
13610
|
}
|
|
13620
13611
|
return;
|
|
13621
13612
|
}
|
|
13622
|
-
if (data
|
|
13613
|
+
if (matchesKey(data, "right") || data === "l") {
|
|
13614
|
+
if (!this.answered()) {
|
|
13615
|
+
this.skip();
|
|
13616
|
+
return;
|
|
13617
|
+
}
|
|
13623
13618
|
if (this.tab < this.questions.length - 1) {
|
|
13624
13619
|
this.tab += 1;
|
|
13625
13620
|
this.cursor = 0;
|
|
@@ -13633,11 +13628,7 @@ var QuestionFlow = class {
|
|
|
13633
13628
|
}
|
|
13634
13629
|
return;
|
|
13635
13630
|
}
|
|
13636
|
-
if (data
|
|
13637
|
-
this.skip();
|
|
13638
|
-
return;
|
|
13639
|
-
}
|
|
13640
|
-
if (data === "\x1B") this.onCancel();
|
|
13631
|
+
if (matchesKey(data, "escape")) this.onCancel();
|
|
13641
13632
|
}
|
|
13642
13633
|
invalidate() {
|
|
13643
13634
|
this.otherInput.invalidate();
|
|
@@ -13680,7 +13671,7 @@ var QuestionFlow = class {
|
|
|
13680
13671
|
const submit = this.submitIdx === 0 ? color.textStrong("Submit") : color.textDim("Submit");
|
|
13681
13672
|
const cancel = this.submitIdx === 1 ? color.textStrong("Cancel") : color.textDim("Cancel");
|
|
13682
13673
|
lines.push(`${this.submitIdx === 0 ? color.primary("→ ") : " "}${submit} ${cancel}`);
|
|
13683
|
-
lines.push(color.textDim("
|
|
13674
|
+
lines.push(color.textDim("↑↓ choose · ← back · ↵ confirm · esc cancel"));
|
|
13684
13675
|
return lines;
|
|
13685
13676
|
}
|
|
13686
13677
|
const question = this.questions[this.tab];
|
|
@@ -13736,14 +13727,14 @@ var QuestionFlow = class {
|
|
|
13736
13727
|
lines.push("");
|
|
13737
13728
|
const optionCount = Math.min(rows.length, 9);
|
|
13738
13729
|
const scrollable = this.lastExpandable;
|
|
13730
|
+
const arrowVerb = this.editingOther ? "→ next" : "→ skip";
|
|
13739
13731
|
const hintParts = [
|
|
13740
13732
|
"↑↓ select",
|
|
13741
13733
|
optionCount > 0 ? `1-${optionCount} choose` : "",
|
|
13742
13734
|
multi ? "↵ toggle" : "↵ confirm",
|
|
13743
13735
|
scrollable ? "pgup/pgdn scroll" : "",
|
|
13744
13736
|
!this.editingOther ? this.bodyExpanded ? "e collapse" : scrollable ? "e expand" : "" : "",
|
|
13745
|
-
this.questions.length > 1 ?
|
|
13746
|
-
"s skip",
|
|
13737
|
+
this.questions.length > 1 ? `← back · ${arrowVerb}` : arrowVerb,
|
|
13747
13738
|
"esc cancel"
|
|
13748
13739
|
].filter((part) => part !== "");
|
|
13749
13740
|
const cancel = "esc cancel";
|
|
@@ -17699,6 +17690,48 @@ function registerTuiCommands(runner, initial) {
|
|
|
17699
17690
|
const sessionCwd = (agent) => agent.session.header.cwd ?? cwd;
|
|
17700
17691
|
const skillTarget = (agent) => resolveLiveSkillTarget(ctx, agent, sessionCwd(agent));
|
|
17701
17692
|
/**
|
|
17693
|
+
* Split a skill invocation's trailing input into the skill name and its
|
|
17694
|
+
* arguments: the first whitespace-bounded token is the name (the public
|
|
17695
|
+
* skill-name grammar), everything after it the arguments. Used by the
|
|
17696
|
+
* per-skill wrappers and `/skill`, so `/name args` never looks up a name
|
|
17697
|
+
* containing the whole rest of the line.
|
|
17698
|
+
* @param raw - the invocation's rawInput ('' for a bare command).
|
|
17699
|
+
* @returns the name token ('' when the input is blank) plus the args.
|
|
17700
|
+
*/
|
|
17701
|
+
const splitSkillLine = (raw) => {
|
|
17702
|
+
const trimmed = raw.trimStart();
|
|
17703
|
+
const space = trimmed.search(/\s/);
|
|
17704
|
+
if (space === -1) return [trimmed.trim(), ...[]];
|
|
17705
|
+
return [trimmed.slice(0, space).trim(), trimmed.slice(space).trimStart()];
|
|
17706
|
+
};
|
|
17707
|
+
/**
|
|
17708
|
+
* Structurally validate a skill's optional resource base, so a malformed
|
|
17709
|
+
* provider-supplied value degrades to no hint instead of throwing inside
|
|
17710
|
+
* the fallback rendering (the adapter's conservative rule — hostile
|
|
17711
|
+
* entries are refused, never coerced or thrown on).
|
|
17712
|
+
* @param value - the loaded skill's `resourceBase` (opaque from the adapter).
|
|
17713
|
+
* @returns the validated resource base, or undefined when unreadable.
|
|
17714
|
+
*/
|
|
17715
|
+
const readResourceBase = (value) => {
|
|
17716
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
17717
|
+
const record = value;
|
|
17718
|
+
switch (record.kind) {
|
|
17719
|
+
case "directory": return typeof record.path === "string" && record.path !== "" ? {
|
|
17720
|
+
kind: "directory",
|
|
17721
|
+
path: record.path
|
|
17722
|
+
} : void 0;
|
|
17723
|
+
case "url": return typeof record.url === "string" && record.url !== "" ? {
|
|
17724
|
+
kind: "url",
|
|
17725
|
+
url: record.url
|
|
17726
|
+
} : void 0;
|
|
17727
|
+
case "opaque": return typeof record.description === "string" && record.description !== "" ? {
|
|
17728
|
+
kind: "opaque",
|
|
17729
|
+
description: record.description
|
|
17730
|
+
} : void 0;
|
|
17731
|
+
default: return;
|
|
17732
|
+
}
|
|
17733
|
+
};
|
|
17734
|
+
/**
|
|
17702
17735
|
* The execution boundary for loading one skill into the live session;
|
|
17703
17736
|
* shared by /skill and the per-skill slash commands. The skill is fetched
|
|
17704
17737
|
* from the CURRENT agent's registry and its invocation policy is RE-CHECKED
|
|
@@ -17706,7 +17739,7 @@ function registerTuiCommands(runner, initial) {
|
|
|
17706
17739
|
* authorization. A model-only skill is refused with an explicit error and
|
|
17707
17740
|
* never injected.
|
|
17708
17741
|
*/
|
|
17709
|
-
const loadSkill = async (agent, name) => {
|
|
17742
|
+
const loadSkill = async (agent, name, args = "") => {
|
|
17710
17743
|
const target = skillTarget(agent);
|
|
17711
17744
|
if (target === void 0) return {
|
|
17712
17745
|
kind: "error",
|
|
@@ -17728,19 +17761,37 @@ function registerTuiCommands(runner, initial) {
|
|
|
17728
17761
|
kind: "error",
|
|
17729
17762
|
text: `skill "${name}" returned a malformed definition`
|
|
17730
17763
|
};
|
|
17731
|
-
const
|
|
17732
|
-
const
|
|
17764
|
+
const line = args.trim() === "" ? "/" + skill.name : "/" + skill.name + " " + args.trimStart();
|
|
17765
|
+
const userMessage = createUserMessage({
|
|
17733
17766
|
content: [{
|
|
17734
17767
|
type: "text",
|
|
17735
|
-
text:
|
|
17768
|
+
text: line
|
|
17736
17769
|
}],
|
|
17737
|
-
source: {
|
|
17738
|
-
kind: "plugin",
|
|
17739
|
-
plugin: "tui-skill"
|
|
17740
|
-
}
|
|
17770
|
+
source: { kind: "user" }
|
|
17741
17771
|
});
|
|
17742
|
-
|
|
17743
|
-
|
|
17772
|
+
const hostSkillLoader = ctx.get("tools")?.get?.("skill", agent);
|
|
17773
|
+
const hostLoadsSkillBody = hostSkillLoader !== void 0 && typeof hostSkillLoader.execute === "function";
|
|
17774
|
+
agent.steer(userMessage);
|
|
17775
|
+
if (!hostLoadsSkillBody) {
|
|
17776
|
+
const body = typeof skill.content === "string" && skill.content !== "" ? skill.content : skill.description;
|
|
17777
|
+
const resourceBase = readResourceBase(skill.resourceBase);
|
|
17778
|
+
agent.inject(createUserMessage({
|
|
17779
|
+
content: [{
|
|
17780
|
+
type: "text",
|
|
17781
|
+
text: renderSkillContent({
|
|
17782
|
+
name: skill.name,
|
|
17783
|
+
provider: typeof skill.provider === "string" && skill.provider !== "" ? skill.provider : "tui",
|
|
17784
|
+
...resourceBase === void 0 ? {} : { resourceBase },
|
|
17785
|
+
content: body
|
|
17786
|
+
})
|
|
17787
|
+
}],
|
|
17788
|
+
source: {
|
|
17789
|
+
kind: "skill-invocation",
|
|
17790
|
+
name: skill.name,
|
|
17791
|
+
form: "instructions"
|
|
17792
|
+
}
|
|
17793
|
+
}));
|
|
17794
|
+
}
|
|
17744
17795
|
return {
|
|
17745
17796
|
kind: "success",
|
|
17746
17797
|
text: "skill " + name + " loaded"
|
|
@@ -17776,9 +17827,9 @@ function registerTuiCommands(runner, initial) {
|
|
|
17776
17827
|
const dispose = commands.register({
|
|
17777
17828
|
name: skill.name,
|
|
17778
17829
|
description: "[skill] " + skill.description,
|
|
17779
|
-
handler: async () => {
|
|
17830
|
+
handler: async (invocation) => {
|
|
17780
17831
|
const agent = await requireAgent();
|
|
17781
|
-
return loadSkill(agent, skill.name);
|
|
17832
|
+
return loadSkill(agent, skill.name, invocation?.rawInput ?? "");
|
|
17782
17833
|
}
|
|
17783
17834
|
});
|
|
17784
17835
|
skillDisposers.set(skill.name, dispose);
|
|
@@ -17824,9 +17875,9 @@ function registerTuiCommands(runner, initial) {
|
|
|
17824
17875
|
const dispose = commands.register({
|
|
17825
17876
|
name,
|
|
17826
17877
|
description: `[skill: revalidating] ${name}`,
|
|
17827
|
-
handler: async () => {
|
|
17878
|
+
handler: async (invocation) => {
|
|
17828
17879
|
const agent = await requireAgent();
|
|
17829
|
-
return loadSkill(agent, name);
|
|
17880
|
+
return loadSkill(agent, name, invocation?.rawInput ?? "");
|
|
17830
17881
|
}
|
|
17831
17882
|
});
|
|
17832
17883
|
skillDisposers.set(name, dispose);
|
|
@@ -17848,8 +17899,8 @@ function registerTuiCommands(runner, initial) {
|
|
|
17848
17899
|
kind: "error",
|
|
17849
17900
|
text: "skill service unavailable"
|
|
17850
17901
|
};
|
|
17851
|
-
const name = invocation.rawInput
|
|
17852
|
-
if (name !== "") return loadSkill(liveAgent, name);
|
|
17902
|
+
const [name, ...args] = splitSkillLine(invocation.rawInput);
|
|
17903
|
+
if (name !== "") return loadSkill(liveAgent, name, args.join(" "));
|
|
17853
17904
|
const catalog = await readHumanSkillCatalog(target.registry, {
|
|
17854
17905
|
cwd: target.cwd,
|
|
17855
17906
|
scope: target.scope
|
package/package.json
CHANGED