@fiale-plus/pi-rogue-advisor 0.1.3 → 0.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiale-plus/pi-rogue-advisor",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "PiRogue advisor extension for Pi — multi-model support, SOTA model suggestion, cache-aware session advisory.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -0,0 +1,31 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { advisorArgumentCompletions, piRogueArgumentCompletions } from "./completions.js";
3
+
4
+ describe("advisor completions", () => {
5
+ it("offers top-level advisor continuations", () => {
6
+ const values = advisorArgumentCompletions("")?.map((i) => i.value);
7
+ expect(values).toEqual(expect.arrayContaining(["status", "config", "checkins", "review"]));
8
+ });
9
+
10
+ it("offers nested review choices", () => {
11
+ const values = advisorArgumentCompletions("review ")?.map((i) => i.value);
12
+ expect(values).toEqual(["light", "strict", "off"]);
13
+ });
14
+
15
+ it("offers check-in choices", () => {
16
+ const values = advisorArgumentCompletions("checkins ")?.map((i) => i.value);
17
+ expect(values).toEqual(expect.arrayContaining(["on", "off", "30", "60"]));
18
+ });
19
+ });
20
+
21
+ describe("pi-rogue cockpit completions", () => {
22
+ it("offers umbrella sections", () => {
23
+ const values = piRogueArgumentCompletions("")?.map((i) => i.value);
24
+ expect(values).toEqual(expect.arrayContaining(["status", "advisor", "orchestration", "help"]));
25
+ });
26
+
27
+ it("fans out to orchestration shortcuts", () => {
28
+ const values = piRogueArgumentCompletions("orchestration ")?.map((i) => i.value);
29
+ expect(values).toEqual(expect.arrayContaining(["goal", "loop", "autoresearch", "autoresearch-lab"]));
30
+ });
31
+ });
@@ -0,0 +1,83 @@
1
+ type CompletionItem = { value: string; label: string; description?: string };
2
+
3
+ function item(value: string, description?: string): CompletionItem {
4
+ return { value, label: value, ...(description ? { description } : {}) };
5
+ }
6
+
7
+ function complete(values: Array<[string, string?]>, prefix: string): CompletionItem[] | null {
8
+ const q = prefix.trimStart().toLowerCase();
9
+ const items = values.map(([value, description]) => item(value, description));
10
+ const filtered = q
11
+ ? items.filter((i) => i.value.startsWith(q))
12
+ : items;
13
+ return filtered.length > 0 ? filtered : null;
14
+ }
15
+
16
+ function completionsForPrefix(prefix: string, topLevel: Array<[string, string?]>, nested: Record<string, Array<[string, string?]>>): CompletionItem[] | null {
17
+ const q = prefix.trimStart().toLowerCase();
18
+ if (!q) return complete(topLevel, q);
19
+
20
+ const [head, ...rest] = q.split(/\s+/);
21
+ if (!head) return complete(topLevel, q);
22
+
23
+ if (rest.length === 0) {
24
+ const top = complete(topLevel, head);
25
+ if (top) return top;
26
+ }
27
+
28
+ const next = nested[head];
29
+ if (next) {
30
+ return complete(next, rest.join(" "));
31
+ }
32
+
33
+ return complete(topLevel, q);
34
+ }
35
+
36
+ const advisorTopLevel: Array<[string, string?]> = [
37
+ ["status", "show status and configuration"],
38
+ ["config", "show full config"],
39
+ ["on", "enable auto mode"],
40
+ ["off", "disable advisor"],
41
+ ["mode", "set auto/manual/off"],
42
+ ["review", "set light/strict/off"],
43
+ ["checkins", "configure mid-hour check-ins"],
44
+ ["checkin", "alias for checkins"],
45
+ ["model", "set or inspect model override"],
46
+ ];
47
+
48
+ const advisorNested: Record<string, Array<[string, string?]>> = {
49
+ mode: [["auto"], ["manual"], ["off"]],
50
+ review: [["light"], ["strict"], ["off"]],
51
+ checkins: [["on"], ["off"], ["10"], ["15"], ["30"], ["60"]],
52
+ checkin: [["on"], ["off"], ["10"], ["15"], ["30"], ["60"]],
53
+ model: [["auto"], ["openai-codex/gpt-5.5"], ["anthropic/claude-opus-4-6"]],
54
+ };
55
+
56
+ const piRogueTopLevel: Array<[string, string?]> = [
57
+ ["status", "show cockpit"],
58
+ ["advisor", "advisor status and check-ins"],
59
+ ["orchestration", "goal/loop/autoresearch shortcuts"],
60
+ ["checkins", "advisor check-ins"],
61
+ ["help", "show cockpit help"],
62
+ ];
63
+
64
+ const piRogueNested: Record<string, Array<[string, string?]>> = {
65
+ advisor: advisorTopLevel,
66
+ orchestration: [
67
+ ["goal", "goal commands"],
68
+ ["loop", "loop commands"],
69
+ ["autoresearch", "solo research flow"],
70
+ ["autoresearch-lab", "parallel research flow"],
71
+ ["status", "show all surfaces"],
72
+ ],
73
+ checkins: advisorNested.checkins,
74
+ help: [["advisor"], ["orchestration"], ["checkins"], ["status"]],
75
+ };
76
+
77
+ export function advisorArgumentCompletions(prefix: string): CompletionItem[] | null {
78
+ return completionsForPrefix(prefix, advisorTopLevel, advisorNested);
79
+ }
80
+
81
+ export function piRogueArgumentCompletions(prefix: string): CompletionItem[] | null {
82
+ return completionsForPrefix(prefix, piRogueTopLevel, piRogueNested);
83
+ }
package/src/extension.ts CHANGED
@@ -5,6 +5,7 @@ import { Box, Text } from "@earendil-works/pi-tui";
5
5
  import { completeSimple, type ThinkingLevel } from "@earendil-works/pi-ai";
6
6
  import { Type } from "typebox";
7
7
  import { featureFile, readText, truncate, writeText } from "./internal.js";
8
+ import { advisorArgumentCompletions, piRogueArgumentCompletions } from "./completions.js";
8
9
  import {
9
10
  appendRouteLog,
10
11
  binaryGatePredict,
@@ -666,10 +667,48 @@ export function registerAdvisor(pi: ExtensionAPI): void {
666
667
  // ── /pi-rogue cockpit ──────────────────────────────────────────────────
667
668
  pi.registerCommand("pi-rogue", {
668
669
  description: "Show PiRogue cockpit: advisor, check-ins, and orchestration command pointers",
669
- handler: async (_args, ctx) => {
670
+ getArgumentCompletions: (prefix: string) => piRogueArgumentCompletions(prefix),
671
+ handler: async (args, ctx) => {
670
672
  const cfg = loadConfig();
671
673
  const state = loadState();
674
+ const arg = String(args ?? "").trim().toLowerCase();
672
675
  setPiRogueStatus(ctx, cfg, state);
676
+
677
+ if (!arg || arg === "status" || arg === "help") {
678
+ ctx.ui.notify(piRogueCockpitText(cfg, state, readText(CURRENT_PATH).trim()), "info");
679
+ return;
680
+ }
681
+
682
+ if (arg.startsWith("advisor")) {
683
+ ctx.ui.notify([
684
+ "Advisor surface:",
685
+ " /advisor status",
686
+ " /advisor config",
687
+ " /advisor checkins on|off|<minutes>",
688
+ " /advisor <question>",
689
+ ].join("\n"), "info");
690
+ return;
691
+ }
692
+
693
+ if (arg.startsWith("orchestration")) {
694
+ ctx.ui.notify([
695
+ "Orchestration surface:",
696
+ " /goal show|clear|list|set <text>",
697
+ " /loop status|off|clear|stop|<interval> <instruction>",
698
+ " /autoresearch status|clear|<instruction>",
699
+ " /autoresearch-lab status|clear|<instruction>",
700
+ ].join("\n"), "info");
701
+ return;
702
+ }
703
+
704
+ if (arg.startsWith("checkins")) {
705
+ ctx.ui.notify([
706
+ `Advisor check-ins: ${cfg.checkins === "off" ? "off" : `${cfg.checkinIntervalMinutes}m`}`,
707
+ "Use /advisor checkins on|off|<minutes> to change it.",
708
+ ].join("\n"), "info");
709
+ return;
710
+ }
711
+
673
712
  ctx.ui.notify(piRogueCockpitText(cfg, state, readText(CURRENT_PATH).trim()), "info");
674
713
  },
675
714
  });
@@ -677,6 +716,7 @@ export function registerAdvisor(pi: ExtensionAPI): void {
677
716
  // ── /advisor command ───────────────────────────────────────────────────
678
717
  pi.registerCommand("advisor", {
679
718
  description: "Senior engineering advisor. Usage: /advisor [on|off|status|config|question]",
719
+ getArgumentCompletions: (prefix: string) => advisorArgumentCompletions(prefix),
680
720
  handler: async (args, ctx) => {
681
721
  const a = String(args ?? "").trim().toLowerCase();
682
722
  const [cmd, ...rest] = a.split(/\s+/);