@bacnh85/pi-subagent 0.16.0 → 0.16.1

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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.16.1 (2026-08-29)
4
+
5
+ ### Added
6
+
7
+ - `/subagent` argument completion: keywords (`list|all|agents|roles|reload|
8
+ refresh|history`), discovered agent names, and `@role` refs.
9
+ - Roles editor rows now offer inline model suggestions (Tab to pick, Enter
10
+ keeps typed text) when run against @bacnh85/pi-config-panel >= 0.1.1; the
11
+ package stays compilable and fully functional on 0.1.0 (suggestions simply
12
+ absent), so no dependency floor bump is required.
13
+
3
14
  ## 0.16.0 (2026-08-23)
4
15
 
5
16
  ### Features
@@ -329,6 +329,20 @@ export default function (pi: ExtensionAPI) {
329
329
  });
330
330
  pi.registerCommand("subagent", {
331
331
  description: "Configure model roles (/subagent), list agents (/subagent list), agent details (/subagent <name>), role detail (/subagent @role), reload definitions (/subagent reload), history (/subagent history)",
332
+ getArgumentCompletions: (prefix) => {
333
+ const ctx = currentCtx;
334
+ const keywords = ["list", "all", "agents", "roles", "reload", "refresh", "history"];
335
+ const vocab = [...keywords];
336
+ if (ctx) {
337
+ const discovery = discoverAgents(ctx.cwd, "both", bundledAgentsDir);
338
+ vocab.push(...discovery.agents.map((a) => a.name));
339
+ try { vocab.push(...Object.keys(readSubagentRoles(ctx).roles).map((r) => `@${r}`)); } catch { /* roles optional */ }
340
+ }
341
+ const q = prefix.trim().toLowerCase();
342
+ const items = vocab.filter((v) => v.toLowerCase().startsWith(q))
343
+ .map((v) => ({ value: v, label: v, description: keywords.includes(v) ? "subagent command" : "agent / role" }));
344
+ return items.length > 0 ? items : null;
345
+ },
332
346
  handler: async (args, ctx) => {
333
347
  const cmd = args.trim().toLowerCase();
334
348
  const discovery = discoverAgents(ctx.cwd, "both", bundledAgentsDir);
@@ -387,10 +401,17 @@ export default function (pi: ExtensionAPI) {
387
401
  }
388
402
  const current = readSubagentRolesGlobal();
389
403
  const working = buildRolesPanelCfg(discovery.agents, current);
404
+ const panelOptions = {
405
+ models: () => {
406
+ try { return ctx.modelRegistry.getAvailable().map((m) => `${m.provider}/${m.id}`); }
407
+ catch { return []; }
408
+ },
409
+ roles: () => [...Object.keys(DEFAULT_ROLES), ...Object.keys(readSubagentRolesGlobal().roles)],
410
+ };
390
411
  await openConfigPanel({
391
412
  ctx,
392
413
  cfg: working,
393
- build: (cfg) => buildRows(cfg, discovery.agents),
414
+ build: (cfg) => buildRows(cfg, discovery.agents, panelOptions),
394
415
  title: "Subagent model roles",
395
416
  onSave: (saved, editedKeys) => {
396
417
  if (!(saved && editedKeys && editedKeys.size > 0)) return;
@@ -14,6 +14,15 @@ import { homedir } from "node:os";
14
14
  import { dirname, join } from "node:path";
15
15
  import { row } from "@bacnh85/pi-config-panel";
16
16
  import type { PanelGroup } from "@bacnh85/pi-config-panel";
17
+
18
+ // ponytail: local structural type — the kernel only reads value/label/
19
+ // description, so this stays compatible with the published 0.1.0 range while
20
+ // completion support ships in 0.1.1 (no static import of new kernel symbols).
21
+ interface CompletionItem {
22
+ value: string;
23
+ label?: string;
24
+ description?: string;
25
+ }
17
26
  import type { AgentConfig } from "./agents.ts";
18
27
  import { DEFAULT_ROLES, readSubagentRoles, type RolesConfig } from "./roles.ts";
19
28
 
@@ -83,6 +92,14 @@ export interface RolesPanelCfg {
83
92
  agentModels: Record<string, string>;
84
93
  }
85
94
 
95
+ /** Completion sources for the panel's model rows (lazy — resolved per keypress). */
96
+ export interface RolesPanelOptions {
97
+ /** Available model refs (`provider/id`), sorted; may be empty before registry sync. */
98
+ models: () => string[];
99
+ /** Known role names (defaults + configured), offered as `@role` on agent rows. */
100
+ roles: () => string[];
101
+ }
102
+
86
103
  /** Seed a working config from current effective settings + bundled agents. */
87
104
  export function buildRolesPanelCfg(agents: AgentConfig[], current: RolesConfig): RolesPanelCfg {
88
105
  const roleNames = new Set([...Object.keys(DEFAULT_ROLES), ...Object.keys(current.roles)]);
@@ -98,21 +115,32 @@ export function buildRolesPanelCfg(agents: AgentConfig[], current: RolesConfig):
98
115
  return cfg;
99
116
  }
100
117
 
101
- /** Build panel groups. Role rows first, then one override row per agent. */
102
- export function buildRows(cfg: RolesPanelCfg, agents: AgentConfig[]): PanelGroup[] {
118
+ /** Build panel groups. Role rows first, then one override row per agent.
119
+ * `options` adds inline model/@role completions when provided (optional so
120
+ * existing unit tests and non-TUI callers stay unchanged). */
121
+ export function buildRows(cfg: RolesPanelCfg, agents: AgentConfig[], options?: RolesPanelOptions): PanelGroup[] {
103
122
  const defaultChain = (name: string) => Array.isArray(DEFAULT_ROLES[name]) ? (DEFAULT_ROLES[name] as string[]).join(", ") : String(DEFAULT_ROLES[name] ?? "");
123
+ const modelItems = (): CompletionItem[] =>
124
+ (options?.models() ?? []).sort().map((ref) => ({ value: ref }));
125
+ const roleItems = (): CompletionItem[] =>
126
+ (options?.roles() ?? []).map((name) => ({ value: `@${name}`, description: "role chain" }));
127
+ // ponytail: opts spread keeps this compilable against kernel 0.1.0 (whose
128
+ // row() opts type lacks `completions`); the runtime contract is additive and
129
+ // 0.1.1+ consumes the field. Drop the cast when the dep floor moves to 0.1.1.
130
+ const withCompletions = (completions: () => CompletionItem[]) =>
131
+ ({ completions }) as unknown as { mask?: boolean };
104
132
  const roleRows = Object.keys(cfg.roles).sort().map((name) => {
105
133
  // Label shows the default chain so blank is meaningful.
106
134
  return row(`role.${name}`, `@${name} (default: ${defaultChain(name) || "none"})`, "string", cfg.roles[name], (v) => {
107
135
  cfg.roles[name] = String(v ?? "").trim();
108
- });
136
+ }, withCompletions(modelItems));
109
137
  });
110
138
  const agentRows = agents.map((agent) =>
111
139
  row(`agent.${agent.name}`, agent.name, "string", cfg.agentModels[agent.name] ?? "", (v) => {
112
140
  const value = String(v ?? "").trim();
113
141
  if (value) cfg.agentModels[agent.name] = value;
114
142
  else delete cfg.agentModels[agent.name];
115
- }),
143
+ }, withCompletions(() => [...modelItems(), ...roleItems()])),
116
144
  );
117
145
  return [
118
146
  { key: "roles", label: "Model roles (chain, blank = default)", rows: roleRows },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacnh85/pi-subagent",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "In-process subagents for Pi with isolated SDK sessions, parallel and chained delegation, and inspectable threads.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -62,9 +62,9 @@
62
62
  "check": "npm run typecheck && npm test"
63
63
  },
64
64
  "peerDependencies": {
65
- "@earendil-works/pi-coding-agent": ">=0.80.0 <0.85.0",
66
- "@earendil-works/pi-ai": ">=0.80.0 <0.85.0",
67
65
  "@earendil-works/pi-agent-core": ">=0.80.0 <0.85.0",
66
+ "@earendil-works/pi-ai": ">=0.80.0 <0.85.0",
67
+ "@earendil-works/pi-coding-agent": ">=0.80.0 <0.85.0",
68
68
  "@earendil-works/pi-tui": ">=0.80.0 <0.85.0",
69
69
  "typebox": ">=1.3.0 <2.0.0"
70
70
  },
@@ -74,14 +74,14 @@
74
74
  "devDependencies": {
75
75
  "@earendil-works/pi-agent-core": "^0.84.0",
76
76
  "@earendil-works/pi-ai": "^0.84.0",
77
- "@earendil-works/pi-coding-agent": "^0.84.0",
78
- "@earendil-works/pi-tui": "^0.84.0",
77
+ "@earendil-works/pi-coding-agent": "^0.84.3",
78
+ "@earendil-works/pi-tui": "^0.84.3",
79
79
  "@types/mocha": "^10.0.10",
80
80
  "@types/node": "^20.19.43",
81
81
  "mocha": "^11.8.0",
82
82
  "tsx": "^4.22.4",
83
- "typescript": "^5.9.3",
84
- "typebox": "^1.3.1"
83
+ "typebox": "^1.3.1",
84
+ "typescript": "^5.9.3"
85
85
  },
86
86
  "overrides": {
87
87
  "serialize-javascript@>=5.0.0 <7.0.5": "^7.0.5",