@esso0428/pi-subagents 0.15.5 → 0.15.6

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 (73) hide show
  1. package/CHANGELOG.md +4 -22
  2. package/README.md +5 -5
  3. package/dist/agent-history-list.d.ts +18 -0
  4. package/dist/agent-history-list.js +68 -0
  5. package/dist/agent-history.d.ts +1 -1
  6. package/dist/agent-history.js +31 -34
  7. package/dist/agent-manager.d.ts +22 -8
  8. package/dist/agent-manager.js +100 -93
  9. package/dist/agent-runner.js +67 -86
  10. package/dist/agent-types.js +27 -45
  11. package/dist/context.js +2 -6
  12. package/dist/cross-extension-rpc.js +5 -9
  13. package/dist/custom-agents.js +15 -18
  14. package/dist/default-agents.js +1 -4
  15. package/dist/enabled-models.js +11 -16
  16. package/dist/env.js +1 -4
  17. package/dist/group-join.js +1 -5
  18. package/dist/index.js +273 -286
  19. package/dist/invocation-config.js +2 -6
  20. package/dist/memory.js +24 -34
  21. package/dist/model-resolver.js +1 -4
  22. package/dist/nico-overrides.js +14 -20
  23. package/dist/output-file.js +16 -22
  24. package/dist/prompts.js +1 -4
  25. package/dist/schedule-store.js +16 -21
  26. package/dist/schedule.js +8 -12
  27. package/dist/settings.js +15 -23
  28. package/dist/skill-loader.js +20 -23
  29. package/dist/status-note.js +1 -4
  30. package/dist/types.d.ts +0 -1
  31. package/dist/types.js +1 -4
  32. package/dist/ui/agent-widget.d.ts +1 -5
  33. package/dist/ui/agent-widget.js +25 -49
  34. package/dist/ui/conversation-blocks.d.ts +18 -0
  35. package/dist/ui/conversation-blocks.js +214 -0
  36. package/dist/ui/conversation-nvim.d.ts +7 -0
  37. package/dist/ui/conversation-nvim.js +116 -0
  38. package/dist/ui/conversation-search.d.ts +38 -0
  39. package/dist/ui/conversation-search.js +123 -0
  40. package/dist/ui/conversation-viewer.d.ts +55 -19
  41. package/dist/ui/conversation-viewer.js +398 -215
  42. package/dist/ui/fleet-list.d.ts +23 -11
  43. package/dist/ui/fleet-list.js +85 -78
  44. package/dist/ui/schedule-menu.js +1 -4
  45. package/dist/ui/viewer-keys.js +7 -10
  46. package/dist/usage.js +4 -10
  47. package/dist/worktree.js +26 -31
  48. package/package.json +1 -1
  49. package/src/agent-history-list.ts +91 -0
  50. package/src/agent-history.ts +12 -17
  51. package/src/agent-manager.ts +108 -81
  52. package/src/agent-runner.ts +5 -13
  53. package/src/index.ts +84 -89
  54. package/src/output-file.ts +1 -1
  55. package/src/types.ts +0 -1
  56. package/src/ui/agent-widget.ts +1 -8
  57. package/src/ui/conversation-blocks.ts +270 -0
  58. package/src/ui/conversation-nvim.ts +127 -0
  59. package/src/ui/conversation-search.ts +161 -0
  60. package/src/ui/conversation-viewer.ts +376 -205
  61. package/src/ui/fleet-list.ts +73 -52
  62. package/test/agent-history-list.test.ts +121 -0
  63. package/test/agent-manager-history.test.ts +59 -58
  64. package/test/agent-menu-history-navigation.test.ts +86 -0
  65. package/test/ui/conversation-blocks.test.ts +72 -0
  66. package/test/ui/conversation-search.test.ts +55 -0
  67. package/test/ui/conversation-viewer.test.ts +132 -0
  68. package/test/ui/fleet-list.test.ts +131 -0
  69. package/dist/ui/markdown-result.d.ts +0 -3
  70. package/dist/ui/markdown-result.js +0 -53
  71. package/src/ui/markdown-result.ts +0 -56
  72. package/test/agent-history.test.ts +0 -63
  73. package/test/ui/markdown-result.test.ts +0 -45
@@ -1,47 +1,30 @@
1
- "use strict";
2
1
  /**
3
2
  * agent-runner.ts — Core execution engine: creates sessions, runs agents, collects results.
4
3
  */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.SUBAGENT_TOOL_NAMES = void 0;
7
- exports.extensionCanonicalName = extensionCanonicalName;
8
- exports.extensionCanonicalNames = extensionCanonicalNames;
9
- exports.parseExtensionsSpec = parseExtensionsSpec;
10
- exports.parseExtSelectors = parseExtSelectors;
11
- exports.installExtensionToolScope = installExtensionToolScope;
12
- exports.normalizeMaxTurns = normalizeMaxTurns;
13
- exports.getDefaultMaxTurns = getDefaultMaxTurns;
14
- exports.setDefaultMaxTurns = setDefaultMaxTurns;
15
- exports.getGraceTurns = getGraceTurns;
16
- exports.setGraceTurns = setGraceTurns;
17
- exports.runAgent = runAgent;
18
- exports.resumeAgent = resumeAgent;
19
- exports.steerAgent = steerAgent;
20
- exports.getAgentConversation = getAgentConversation;
21
- const node_fs_1 = require("node:fs");
22
- const node_os_1 = require("node:os");
23
- const node_path_1 = require("node:path");
24
- const pi_coding_agent_1 = require("@earendil-works/pi-coding-agent");
25
- const agent_types_js_1 = require("./agent-types.js");
26
- const context_js_1 = require("./context.js");
27
- const default_agents_js_1 = require("./default-agents.js");
28
- const env_js_1 = require("./env.js");
29
- const memory_js_1 = require("./memory.js");
30
- const prompts_js_1 = require("./prompts.js");
31
- const skill_loader_js_1 = require("./skill-loader.js");
4
+ import { readFileSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ import { basename, dirname, isAbsolute, join, resolve } from "node:path";
7
+ import { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager, SettingsManager, } from "@earendil-works/pi-coding-agent";
8
+ import { BUILTIN_TOOL_NAMES, getAgentConfig, getConfig, getMemoryToolNames, getReadOnlyMemoryToolNames, getToolNamesForType } from "./agent-types.js";
9
+ import { buildParentContext, extractText } from "./context.js";
10
+ import { DEFAULT_AGENTS } from "./default-agents.js";
11
+ import { detectEnv } from "./env.js";
12
+ import { buildMemoryBlock, buildReadOnlyMemoryBlock } from "./memory.js";
13
+ import { buildAgentPrompt } from "./prompts.js";
14
+ import { preloadSkills } from "./skill-loader.js";
32
15
  /**
33
16
  * Tool names registered by THIS extension. Single source of truth so the
34
17
  * registration sites (index.ts) and the subagent exclusion list below can't
35
18
  * drift apart. These are our own tools, not pi built-ins, so they can't be
36
19
  * derived from pi — but they only need defining once.
37
20
  */
38
- exports.SUBAGENT_TOOL_NAMES = {
21
+ export const SUBAGENT_TOOL_NAMES = {
39
22
  AGENT: "Agent",
40
23
  GET_RESULT: "get_subagent_result",
41
24
  STEER: "steer_subagent",
42
25
  };
43
26
  /** Names of tools registered by this extension that subagents must NOT inherit. */
44
- const EXCLUDED_TOOL_NAMES = Object.values(exports.SUBAGENT_TOOL_NAMES);
27
+ const EXCLUDED_TOOL_NAMES = Object.values(SUBAGENT_TOOL_NAMES);
45
28
  /**
46
29
  * Canonical name of an extension for `extensions: [...]` allowlist matching.
47
30
  * Lowercased — extension names match case-insensitively so `extensions: [Mcp]`
@@ -49,10 +32,10 @@ const EXCLUDED_TOOL_NAMES = Object.values(exports.SUBAGENT_TOOL_NAMES);
49
32
  * Directory extensions (`foo/index.ts`) resolve to the parent directory name;
50
33
  * single-file extensions to the basename minus `.ts`/`.js`.
51
34
  */
52
- function extensionCanonicalName(extPath) {
53
- const base = (0, node_path_1.basename)(extPath);
35
+ export function extensionCanonicalName(extPath) {
36
+ const base = basename(extPath);
54
37
  const name = base === "index.ts" || base === "index.js"
55
- ? (0, node_path_1.basename)((0, node_path_1.dirname)(extPath))
38
+ ? basename(dirname(extPath))
56
39
  : base.replace(/\.(ts|js)$/, "");
57
40
  return name.toLowerCase();
58
41
  }
@@ -76,18 +59,18 @@ function extensionCanonicalName(extPath) {
76
59
  * co-located file to `pi-subagents`.
77
60
  */
78
61
  function extensionPackageName(extPath) {
79
- const entry = (0, node_path_1.resolve)(extPath);
80
- let dir = (0, node_path_1.dirname)(extPath);
62
+ const entry = resolve(extPath);
63
+ let dir = dirname(extPath);
81
64
  for (;;) {
82
65
  // Climbing into node_modules means we've left the owning package's tree.
83
- if ((0, node_path_1.basename)(dir) === "node_modules")
66
+ if (basename(dir) === "node_modules")
84
67
  return undefined;
85
68
  let pkg;
86
69
  try {
87
- pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(dir, "package.json"), "utf-8"));
70
+ pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8"));
88
71
  }
89
72
  catch {
90
- const parent = (0, node_path_1.dirname)(dir);
73
+ const parent = dirname(dir);
91
74
  if (parent === dir)
92
75
  return undefined; // walked to the filesystem root
93
76
  dir = parent;
@@ -97,7 +80,7 @@ function extensionPackageName(extPath) {
97
80
  const entries = pkg.pi?.extensions;
98
81
  if (typeof pkg.name === "string" &&
99
82
  Array.isArray(entries) &&
100
- entries.some((e) => typeof e === "string" && (0, node_path_1.resolve)(dir, e) === entry)) {
83
+ entries.some((e) => typeof e === "string" && resolve(dir, e) === entry)) {
101
84
  const short = pkg.name.startsWith("@") ? pkg.name.slice(pkg.name.indexOf("/") + 1) : pkg.name;
102
85
  return short.toLowerCase();
103
86
  }
@@ -112,7 +95,7 @@ function extensionPackageName(extPath) {
112
95
  * otherwise only ever match as `src` (the source directory), never by its
113
96
  * package name. The path-derived name is preserved, so it keeps matching too.
114
97
  */
115
- function extensionCanonicalNames(extPath) {
98
+ export function extensionCanonicalNames(extPath) {
116
99
  const canonical = extensionCanonicalName(extPath);
117
100
  const pkg = extensionPackageName(extPath);
118
101
  return pkg && pkg !== canonical ? [canonical, pkg] : [canonical];
@@ -128,7 +111,7 @@ function extensionCanonicalNames(extPath) {
128
111
  * everything by canonical name, so path-loaded extensions are matched via their name
129
112
  * rather than their post-staging `Extension.path`.
130
113
  */
131
- function parseExtensionsSpec(entries, cwd) {
114
+ export function parseExtensionsSpec(entries, cwd) {
132
115
  const names = new Set();
133
116
  const paths = [];
134
117
  let wildcard = false;
@@ -146,9 +129,9 @@ function parseExtensionsSpec(entries, cwd) {
146
129
  }
147
130
  let p = entry;
148
131
  if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
149
- p = (0, node_os_1.homedir)() + p.slice(1);
132
+ p = homedir() + p.slice(1);
150
133
  }
151
- const abs = (0, node_path_1.isAbsolute)(p) ? p : (0, node_path_1.resolve)(cwd, p);
134
+ const abs = isAbsolute(p) ? p : resolve(cwd, p);
152
135
  paths.push(abs);
153
136
  names.add(extensionCanonicalName(abs));
154
137
  }
@@ -164,7 +147,7 @@ function parseExtensionsSpec(entries, cwd) {
164
147
  * `ext:foo` alongside `ext:foo/bar` leaves narrowing in effect (narrowing wins).
165
148
  * The split is on the first `/`; extension canonical names never contain `/`.
166
149
  */
167
- function parseExtSelectors(entries) {
150
+ export function parseExtSelectors(entries) {
168
151
  const extNames = new Set();
169
152
  const narrowing = new Map();
170
153
  for (const raw of entries) {
@@ -218,7 +201,7 @@ function parseExtSelectors(entries) {
218
201
  * Only meaningful when extensions are loaded — under `noExtensions`/`isolated` the
219
202
  * static `allowedToolNames` allowlist already gates the registry itself.
220
203
  */
221
- function installExtensionToolScope(session, ctx) {
204
+ export function installExtensionToolScope(session, ctx) {
222
205
  const { loader, toolNames, disallowedSet, extNames, narrowing } = ctx;
223
206
  // The names allowed right now. Mirrors the `ext:` opt-in flip: when any `ext:`
224
207
  // selector is present, extension tools become an explicit allowlist — a loaded
@@ -277,21 +260,21 @@ function installExtensionToolScope(session, ctx) {
277
260
  /** Default max turns. undefined = unlimited (no turn limit). */
278
261
  let defaultMaxTurns;
279
262
  /** Normalize max turns. undefined or 0 = unlimited, otherwise minimum 1. */
280
- function normalizeMaxTurns(n) {
263
+ export function normalizeMaxTurns(n) {
281
264
  if (n == null || n === 0)
282
265
  return undefined;
283
266
  return Math.max(1, n);
284
267
  }
285
268
  /** Get the default max turns value. undefined = unlimited. */
286
- function getDefaultMaxTurns() { return defaultMaxTurns; }
269
+ export function getDefaultMaxTurns() { return defaultMaxTurns; }
287
270
  /** Set the default max turns value. undefined or 0 = unlimited, otherwise minimum 1. */
288
- function setDefaultMaxTurns(n) { defaultMaxTurns = normalizeMaxTurns(n); }
271
+ export function setDefaultMaxTurns(n) { defaultMaxTurns = normalizeMaxTurns(n); }
289
272
  /** Additional turns allowed after the soft limit steer message. */
290
273
  let graceTurns = 5;
291
274
  /** Get the grace turns value. */
292
- function getGraceTurns() { return graceTurns; }
275
+ export function getGraceTurns() { return graceTurns; }
293
276
  /** Set the grace turns value (minimum 1). */
294
- function setGraceTurns(n) { graceTurns = Math.max(1, n); }
277
+ export function setGraceTurns(n) { graceTurns = Math.max(1, n); }
295
278
  /**
296
279
  * Try to find the right model for an agent type.
297
280
  * Priority: explicit option > config.model > parent model.
@@ -346,7 +329,7 @@ function getLastAssistantText(session, startIndex = 0) {
346
329
  const msg = session.messages[i];
347
330
  if (msg.role !== "assistant")
348
331
  continue;
349
- const text = (0, context_js_1.extractText)(msg.content).trim();
332
+ const text = extractText(msg.content).trim();
350
333
  if (text)
351
334
  return text;
352
335
  }
@@ -374,7 +357,7 @@ function finalTurnError(session, startIndex = 0) {
374
357
  if (msg.stopReason === "error") {
375
358
  return msg.errorMessage?.trim() || "provider error with no output";
376
359
  }
377
- if (msg.stopReason === "length" && !(0, context_js_1.extractText)(msg.content).trim()) {
360
+ if (msg.stopReason === "length" && !extractText(msg.content).trim()) {
378
361
  return "run hit the output token limit before producing any text";
379
362
  }
380
363
  return undefined;
@@ -396,20 +379,20 @@ function resolveConfiguredSessionDir(sessionDir, cwd) {
396
379
  if (!sessionDir)
397
380
  return undefined;
398
381
  if (sessionDir === "~" || sessionDir.startsWith("~/"))
399
- return (0, node_path_1.resolve)((0, node_os_1.homedir)(), sessionDir.slice(2));
400
- if ((0, node_path_1.isAbsolute)(sessionDir))
382
+ return resolve(homedir(), sessionDir.slice(2));
383
+ if (isAbsolute(sessionDir))
401
384
  return sessionDir;
402
- return (0, node_path_1.resolve)(cwd, sessionDir);
385
+ return resolve(cwd, sessionDir);
403
386
  }
404
- async function runAgent(ctx, type, prompt, options) {
405
- const config = (0, agent_types_js_1.getConfig)(type);
406
- const agentConfig = (0, agent_types_js_1.getAgentConfig)(type);
387
+ export async function runAgent(ctx, type, prompt, options) {
388
+ const config = getConfig(type);
389
+ const agentConfig = getAgentConfig(type);
407
390
  // Resolve working directory: worktree override > parent cwd
408
391
  const effectiveCwd = options.cwd ?? ctx.cwd;
409
392
  // Filesystem work happens in effectiveCwd; config discovery in configCwd.
410
393
  // They differ only for SpawnOptions.cwd spawns (config stays with the parent).
411
394
  const configCwd = options.configCwd ?? effectiveCwd;
412
- const env = await (0, env_js_1.detectEnv)(options.pi, effectiveCwd);
395
+ const env = await detectEnv(options.pi, effectiveCwd);
413
396
  // Get parent system prompt for append-mode agents
414
397
  const parentSystemPrompt = ctx.getSystemPrompt();
415
398
  // Build prompt extras (memory, skill preloading)
@@ -422,12 +405,12 @@ async function runAgent(ctx, type, prompt, options) {
422
405
  const skills = options.isolated ? false : config.skills;
423
406
  // Skill preloading: when skills is string[], preload their content into prompt
424
407
  if (Array.isArray(skills)) {
425
- const loaded = (0, skill_loader_js_1.preloadSkills)(skills, configCwd);
408
+ const loaded = preloadSkills(skills, configCwd);
426
409
  if (loaded.length > 0) {
427
410
  extras.skillBlocks = loaded;
428
411
  }
429
412
  }
430
- let toolNames = (0, agent_types_js_1.getToolNamesForType)(type);
413
+ let toolNames = getToolNamesForType(type);
431
414
  // Persistent memory: detect write capability and branch accordingly.
432
415
  // Account for disallowedTools — a tool in the base set but on the denylist is not truly available.
433
416
  if (agentConfig?.memory) {
@@ -437,36 +420,36 @@ async function runAgent(ctx, type, prompt, options) {
437
420
  const hasWriteTools = effectivelyHas("write") || effectivelyHas("edit");
438
421
  if (hasWriteTools) {
439
422
  // Read-write memory: add any missing memory tool names (read/write/edit)
440
- const extraNames = (0, agent_types_js_1.getMemoryToolNames)(existingNames);
423
+ const extraNames = getMemoryToolNames(existingNames);
441
424
  if (extraNames.length > 0)
442
425
  toolNames = [...toolNames, ...extraNames];
443
- extras.memoryBlock = (0, memory_js_1.buildMemoryBlock)(agentConfig.name, agentConfig.memory, configCwd);
426
+ extras.memoryBlock = buildMemoryBlock(agentConfig.name, agentConfig.memory, configCwd);
444
427
  }
445
428
  else {
446
429
  // Read-only memory: only add read tool name, use read-only prompt
447
- const extraNames = (0, agent_types_js_1.getReadOnlyMemoryToolNames)(existingNames);
430
+ const extraNames = getReadOnlyMemoryToolNames(existingNames);
448
431
  if (extraNames.length > 0)
449
432
  toolNames = [...toolNames, ...extraNames];
450
- extras.memoryBlock = (0, memory_js_1.buildReadOnlyMemoryBlock)(agentConfig.name, agentConfig.memory, configCwd);
433
+ extras.memoryBlock = buildReadOnlyMemoryBlock(agentConfig.name, agentConfig.memory, configCwd);
451
434
  }
452
435
  }
453
436
  // Build system prompt from agent config
454
437
  let systemPrompt;
455
438
  if (agentConfig) {
456
- systemPrompt = (0, prompts_js_1.buildAgentPrompt)(agentConfig, effectiveCwd, env, parentSystemPrompt, extras);
439
+ systemPrompt = buildAgentPrompt(agentConfig, effectiveCwd, env, parentSystemPrompt, extras);
457
440
  }
458
441
  else {
459
442
  // Unknown type fallback: spread the canonical general-purpose config (defensive —
460
443
  // unreachable in practice since index.ts resolves unknown types before calling runAgent).
461
- const fallback = default_agents_js_1.DEFAULT_AGENTS.get("general-purpose");
444
+ const fallback = DEFAULT_AGENTS.get("general-purpose");
462
445
  if (!fallback)
463
446
  throw new Error(`No fallback config available for unknown type "${type}"`);
464
- systemPrompt = (0, prompts_js_1.buildAgentPrompt)({ ...fallback, name: type }, effectiveCwd, env, parentSystemPrompt, extras);
447
+ systemPrompt = buildAgentPrompt({ ...fallback, name: type }, effectiveCwd, env, parentSystemPrompt, extras);
465
448
  }
466
449
  // When skills is string[], we've already preloaded them into the prompt.
467
450
  // Still pass noSkills: true since we don't need the skill loader to load them again.
468
451
  const noSkills = skills === false || Array.isArray(skills);
469
- const agentDir = (0, pi_coding_agent_1.getAgentDir)();
452
+ const agentDir = getAgentDir();
470
453
  // Extension loading:
471
454
  // - true → all default-discovered extensions
472
455
  // - false → none (noExtensions)
@@ -519,7 +502,7 @@ async function runAgent(ctx, type, prompt, options) {
519
502
  }),
520
503
  };
521
504
  };
522
- const loader = new pi_coding_agent_1.DefaultResourceLoader({
505
+ const loader = new DefaultResourceLoader({
523
506
  cwd: configCwd,
524
507
  agentDir,
525
508
  noExtensions,
@@ -538,7 +521,7 @@ async function runAgent(ctx, type, prompt, options) {
538
521
  // this produced a silently broken agent (#75) — pi-mono accepted the bogus name
539
522
  // into the allowlist, then dropped it at registration with no signal back.
540
523
  if (agentConfig?.builtinToolNames?.length) {
541
- const knownBuiltins = new Set(agent_types_js_1.BUILTIN_TOOL_NAMES);
524
+ const knownBuiltins = new Set(BUILTIN_TOOL_NAMES);
542
525
  for (const name of agentConfig.builtinToolNames) {
543
526
  if (!knownBuiltins.has(name)) {
544
527
  options.onToolActivity?.({
@@ -641,7 +624,7 @@ async function runAgent(ctx, type, prompt, options) {
641
624
  else {
642
625
  const denyTools = new Set(EXCLUDED_TOOL_NAMES);
643
626
  // Keep only the built-ins the agent asked for — deny the rest.
644
- for (const name of agent_types_js_1.BUILTIN_TOOL_NAMES) {
627
+ for (const name of BUILTIN_TOOL_NAMES) {
645
628
  if (!builtinToolNameSet.has(name))
646
629
  denyTools.add(name);
647
630
  }
@@ -651,25 +634,23 @@ async function runAgent(ctx, type, prompt, options) {
651
634
  }
652
635
  sessionExcludeTools = [...denyTools];
653
636
  }
654
- const settingsManager = pi_coding_agent_1.SettingsManager.create(configCwd, agentDir);
637
+ const settingsManager = SettingsManager.create(configCwd, agentDir);
655
638
  const configuredSessionDir = resolveConfiguredSessionDir(agentConfig?.sessionDir, effectiveCwd);
656
639
  const defaultSessionDir = process.env.PI_CODING_AGENT_SESSION_DIR ?? settingsManager.getSessionDir?.();
657
640
  const sessionManager = agentConfig?.persistSession
658
- ? pi_coding_agent_1.SessionManager.create(effectiveCwd, configuredSessionDir ?? defaultSessionDir)
659
- : pi_coding_agent_1.SessionManager.inMemory(effectiveCwd);
641
+ ? SessionManager.create(effectiveCwd, configuredSessionDir ?? defaultSessionDir)
642
+ : SessionManager.inMemory(effectiveCwd);
660
643
  // Pi 0.80.8 replaced createAgentSession's modelRegistry option with
661
644
  // modelRuntime, but ExtensionContext still exposes only the registry facade.
662
645
  // Pass both so the full supported Pi range retains the parent's providers.
663
- const parentModelRuntime = ctx.modelRegistry.runtime;
646
+ const parentModelRuntime = ctx.modelRegistry.runtime ?? undefined;
664
647
  const sessionOpts = {
665
648
  cwd: effectiveCwd,
666
649
  agentDir,
667
650
  sessionManager,
668
651
  settingsManager,
669
652
  modelRegistry: ctx.modelRegistry,
670
- ...(parentModelRuntime != null && {
671
- modelRuntime: parentModelRuntime,
672
- }),
653
+ ...(parentModelRuntime !== undefined && { modelRuntime: parentModelRuntime }),
673
654
  model,
674
655
  tools: sessionTools,
675
656
  resourceLoader: loader,
@@ -680,7 +661,7 @@ async function runAgent(ctx, type, prompt, options) {
680
661
  if (thinkingLevel) {
681
662
  sessionOpts.thinkingLevel = thinkingLevel;
682
663
  }
683
- const { session } = await (0, pi_coding_agent_1.createAgentSession)(sessionOpts);
664
+ const { session } = await createAgentSession(sessionOpts);
684
665
  const baseSessionName = agentConfig?.name ?? type;
685
666
  session.setSessionName(options.agentId ? `${baseSessionName}#${options.agentId.slice(0, 8)}` : baseSessionName);
686
667
  // Bind extensions so that session_start fires and extensions can initialize
@@ -763,7 +744,7 @@ async function runAgent(ctx, type, prompt, options) {
763
744
  // Build the effective prompt: optionally prepend parent context
764
745
  let effectivePrompt = prompt;
765
746
  if (options.inheritContext) {
766
- const parentContext = (0, context_js_1.buildParentContext)(ctx);
747
+ const parentContext = buildParentContext(ctx);
767
748
  if (parentContext) {
768
749
  effectivePrompt = parentContext + prompt;
769
750
  }
@@ -785,7 +766,7 @@ async function runAgent(ctx, type, prompt, options) {
785
766
  /**
786
767
  * Send a new prompt to an existing session (resume).
787
768
  */
788
- async function resumeAgent(session, prompt, options = {}) {
769
+ export async function resumeAgent(session, prompt, options = {}) {
789
770
  // Boundary for the history fallback: the session already holds prior turns,
790
771
  // so only assistant text produced by THIS resume prompt counts as its output
791
772
  // — a failed resume must not surface the previous turn's answer (#144).
@@ -829,19 +810,19 @@ async function resumeAgent(session, prompt, options = {}) {
829
810
  * Send a steering message to a running subagent.
830
811
  * The message will interrupt the agent after its current tool execution.
831
812
  */
832
- async function steerAgent(session, message) {
813
+ export async function steerAgent(session, message) {
833
814
  await session.steer(message);
834
815
  }
835
816
  /**
836
817
  * Get the subagent's conversation messages as formatted text.
837
818
  */
838
- function getAgentConversation(session) {
819
+ export function getAgentConversation(session) {
839
820
  const parts = [];
840
821
  for (const msg of session.messages) {
841
822
  if (msg.role === "user") {
842
823
  const text = typeof msg.content === "string"
843
824
  ? msg.content
844
- : (0, context_js_1.extractText)(msg.content);
825
+ : extractText(msg.content);
845
826
  if (text.trim())
846
827
  parts.push(`[User]: ${text.trim()}`);
847
828
  }
@@ -860,7 +841,7 @@ function getAgentConversation(session) {
860
841
  parts.push(`[Tool Calls]:\n${toolCalls.join("\n")}`);
861
842
  }
862
843
  else if (msg.role === "toolResult") {
863
- const text = (0, context_js_1.extractText)(msg.content);
844
+ const text = extractText(msg.content);
864
845
  const truncated = text.length > 200 ? text.slice(0, 200) + "..." : text;
865
846
  parts.push(`[Tool Result (${msg.toolName})]: ${truncated}`);
866
847
  }
@@ -1,30 +1,12 @@
1
- "use strict";
2
1
  /**
3
2
  * agent-types.ts — Unified agent type registry.
4
3
  *
5
4
  * Merges embedded default agents with user-defined agents from .pi/agents/*.md, .agents/agents/*.md, and global agents.
6
5
  * User agents override defaults with the same name. Disabled agents are kept but excluded from spawning.
7
6
  */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.BUILTIN_TOOL_NAMES = void 0;
10
- exports.isDefaultsDisabled = isDefaultsDisabled;
11
- exports.setDefaultsDisabled = setDefaultsDisabled;
12
- exports.registerAgents = registerAgents;
13
- exports.applyNicoOverrides = applyNicoOverrides;
14
- exports.resolveType = resolveType;
15
- exports.getAgentConfig = getAgentConfig;
16
- exports.getAvailableTypes = getAvailableTypes;
17
- exports.getAllTypes = getAllTypes;
18
- exports.getDefaultAgentNames = getDefaultAgentNames;
19
- exports.getUserAgentNames = getUserAgentNames;
20
- exports.isValidType = isValidType;
21
- exports.getMemoryToolNames = getMemoryToolNames;
22
- exports.getReadOnlyMemoryToolNames = getReadOnlyMemoryToolNames;
23
- exports.getToolNamesForType = getToolNamesForType;
24
- exports.getConfig = getConfig;
25
- const pi_coding_agent_1 = require("@earendil-works/pi-coding-agent");
26
- const default_agents_js_1 = require("./default-agents.js");
27
- const nico_overrides_js_1 = require("./nico-overrides.js");
7
+ import { createCodingTools, createReadOnlyTools } from "@earendil-works/pi-coding-agent";
8
+ import { DEFAULT_AGENTS } from "./default-agents.js";
9
+ import { applyNicoOverridesToMap, readNicoAgentOverrides } from "./nico-overrides.js";
28
10
  /**
29
11
  * All known built-in tool names, derived from pi's own tool factories rather
30
12
  * than hardcoded so the set tracks pi-mono if it adds/renames a built-in.
@@ -33,27 +15,27 @@ const nico_overrides_js_1 = require("./nico-overrides.js");
33
15
  * (read, bash, edit, write, grep, find, ls). The `cwd` only binds tool
34
16
  * operations we never invoke here — we read each tool's `.name` and discard it.
35
17
  */
36
- exports.BUILTIN_TOOL_NAMES = [
37
- ...new Set([...(0, pi_coding_agent_1.createCodingTools)("."), ...(0, pi_coding_agent_1.createReadOnlyTools)(".")].map((t) => t.name)),
18
+ export const BUILTIN_TOOL_NAMES = [
19
+ ...new Set([...createCodingTools("."), ...createReadOnlyTools(".")].map((t) => t.name)),
38
20
  ];
39
21
  /** Unified runtime registry of all agents (defaults + user-defined). */
40
22
  const agents = new Map();
41
23
  /** When true, DEFAULT_AGENTS are skipped during registration. */
42
24
  let disableDefaults = false;
43
25
  /** Check whether default agents are disabled. */
44
- function isDefaultsDisabled() { return disableDefaults; }
26
+ export function isDefaultsDisabled() { return disableDefaults; }
45
27
  /** Set whether default agents are disabled. */
46
- function setDefaultsDisabled(b) { disableDefaults = b; }
28
+ export function setDefaultsDisabled(b) { disableDefaults = b; }
47
29
  /**
48
30
  * Register agents into the unified registry.
49
31
  * Starts with DEFAULT_AGENTS, then overlays user agents (overrides defaults with same name).
50
32
  * Disabled agents (enabled === false) are kept in the registry but excluded from spawning.
51
33
  */
52
- function registerAgents(userAgents) {
34
+ export function registerAgents(userAgents) {
53
35
  agents.clear();
54
36
  // Start with defaults (unless disabled via settings)
55
37
  if (!disableDefaults) {
56
- for (const [name, config] of default_agents_js_1.DEFAULT_AGENTS) {
38
+ for (const [name, config] of DEFAULT_AGENTS) {
57
39
  agents.set(name, config);
58
40
  }
59
41
  }
@@ -68,9 +50,9 @@ function registerAgents(userAgents) {
68
50
  * them as the highest-priority layer. Auto-registers agents that don't
69
51
  * exist in the registry yet.
70
52
  */
71
- function applyNicoOverrides() {
72
- const { overrides, defaultModel } = (0, nico_overrides_js_1.readNicoAgentOverrides)(process.cwd());
73
- (0, nico_overrides_js_1.applyNicoOverridesToMap)(agents, overrides, defaultModel);
53
+ export function applyNicoOverrides() {
54
+ const { overrides, defaultModel } = readNicoAgentOverrides(process.cwd());
55
+ applyNicoOverridesToMap(agents, overrides, defaultModel);
74
56
  }
75
57
  /** Case-insensitive key resolution. */
76
58
  function resolveKey(name) {
@@ -84,38 +66,38 @@ function resolveKey(name) {
84
66
  return undefined;
85
67
  }
86
68
  /** Resolve a type name case-insensitively. Returns the canonical key or undefined. */
87
- function resolveType(name) {
69
+ export function resolveType(name) {
88
70
  return resolveKey(name);
89
71
  }
90
72
  /** Get the agent config for a type (case-insensitive). */
91
- function getAgentConfig(name) {
73
+ export function getAgentConfig(name) {
92
74
  const key = resolveKey(name);
93
75
  return key ? agents.get(key) : undefined;
94
76
  }
95
77
  /** Get all enabled type names (for spawning and tool descriptions). */
96
- function getAvailableTypes() {
78
+ export function getAvailableTypes() {
97
79
  return [...agents.entries()]
98
80
  .filter(([_, config]) => config.enabled !== false)
99
81
  .map(([name]) => name);
100
82
  }
101
83
  /** Get all type names including disabled (for UI listing). */
102
- function getAllTypes() {
84
+ export function getAllTypes() {
103
85
  return [...agents.keys()];
104
86
  }
105
87
  /** Get names of default agents currently in the registry. */
106
- function getDefaultAgentNames() {
88
+ export function getDefaultAgentNames() {
107
89
  return [...agents.entries()]
108
90
  .filter(([_, config]) => config.isDefault === true)
109
91
  .map(([name]) => name);
110
92
  }
111
93
  /** Get names of user-defined agents (non-defaults) currently in the registry. */
112
- function getUserAgentNames() {
94
+ export function getUserAgentNames() {
113
95
  return [...agents.entries()]
114
96
  .filter(([_, config]) => config.isDefault !== true)
115
97
  .map(([name]) => name);
116
98
  }
117
99
  /** Check if a type is valid and enabled (case-insensitive). */
118
- function isValidType(type) {
100
+ export function isValidType(type) {
119
101
  const key = resolveKey(type);
120
102
  if (!key)
121
103
  return false;
@@ -126,7 +108,7 @@ const MEMORY_TOOL_NAMES = ["read", "write", "edit"];
126
108
  /**
127
109
  * Get memory tool names (read/write/edit) not already in the provided set.
128
110
  */
129
- function getMemoryToolNames(existingToolNames) {
111
+ export function getMemoryToolNames(existingToolNames) {
130
112
  return MEMORY_TOOL_NAMES.filter(n => !existingToolNames.has(n));
131
113
  }
132
114
  /** Tool names needed for read-only memory access. */
@@ -134,27 +116,27 @@ const READONLY_MEMORY_TOOL_NAMES = ["read"];
134
116
  /**
135
117
  * Get read-only memory tool names not already in the provided set.
136
118
  */
137
- function getReadOnlyMemoryToolNames(existingToolNames) {
119
+ export function getReadOnlyMemoryToolNames(existingToolNames) {
138
120
  return READONLY_MEMORY_TOOL_NAMES.filter(n => !existingToolNames.has(n));
139
121
  }
140
122
  /** Get built-in tool names for a type (case-insensitive). */
141
- function getToolNamesForType(type) {
123
+ export function getToolNamesForType(type) {
142
124
  const key = resolveKey(type);
143
125
  const raw = key ? agents.get(key) : undefined;
144
126
  const config = raw?.enabled !== false ? raw : undefined;
145
127
  // `undefined` (definition omitted the field) → all built-ins; an explicit `[]`
146
128
  // (`tools: none` or a `tools:` with only `ext:` entries) → zero built-ins.
147
- return config?.builtinToolNames ?? [...exports.BUILTIN_TOOL_NAMES];
129
+ return config?.builtinToolNames ?? [...BUILTIN_TOOL_NAMES];
148
130
  }
149
131
  /** Get config for a type (case-insensitive, returns a SubagentTypeConfig-compatible object). Falls back to general-purpose. */
150
- function getConfig(type) {
132
+ export function getConfig(type) {
151
133
  const key = resolveKey(type);
152
134
  const config = key ? agents.get(key) : undefined;
153
135
  if (config && config.enabled !== false) {
154
136
  return {
155
137
  displayName: config.displayName ?? config.name,
156
138
  description: config.description,
157
- builtinToolNames: config.builtinToolNames ?? exports.BUILTIN_TOOL_NAMES,
139
+ builtinToolNames: config.builtinToolNames ?? BUILTIN_TOOL_NAMES,
158
140
  extensions: config.extensions,
159
141
  excludeExtensions: config.excludeExtensions,
160
142
  skills: config.skills,
@@ -167,7 +149,7 @@ function getConfig(type) {
167
149
  return {
168
150
  displayName: gp.displayName ?? gp.name,
169
151
  description: gp.description,
170
- builtinToolNames: gp.builtinToolNames ?? exports.BUILTIN_TOOL_NAMES,
152
+ builtinToolNames: gp.builtinToolNames ?? BUILTIN_TOOL_NAMES,
171
153
  extensions: gp.extensions,
172
154
  excludeExtensions: gp.excludeExtensions,
173
155
  skills: gp.skills,
@@ -178,7 +160,7 @@ function getConfig(type) {
178
160
  return {
179
161
  displayName: "Agent",
180
162
  description: "General-purpose agent for complex, multi-step tasks",
181
- builtinToolNames: exports.BUILTIN_TOOL_NAMES,
163
+ builtinToolNames: BUILTIN_TOOL_NAMES,
182
164
  extensions: true,
183
165
  skills: true,
184
166
  promptMode: "append",
package/dist/context.js CHANGED
@@ -1,12 +1,8 @@
1
- "use strict";
2
1
  /**
3
2
  * context.ts — Extract parent conversation context for subagent inheritance.
4
3
  */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.extractText = extractText;
7
- exports.buildParentContext = buildParentContext;
8
4
  /** Extract text from a message content block array. */
9
- function extractText(content) {
5
+ export function extractText(content) {
10
6
  return content
11
7
  .filter((c) => c.type === "text")
12
8
  .map((c) => c.text ?? "")
@@ -17,7 +13,7 @@ function extractText(content) {
17
13
  * Used when inherit_context is true to give the subagent visibility
18
14
  * into what has been discussed/done so far.
19
15
  */
20
- function buildParentContext(ctx) {
16
+ export function buildParentContext(ctx) {
21
17
  const entries = ctx.sessionManager.getBranch();
22
18
  if (!entries || entries.length === 0)
23
19
  return "";
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Cross-extension RPC handlers for the subagents extension.
4
3
  *
@@ -9,12 +8,9 @@
9
8
  * success → { success: true, data?: T }
10
9
  * error → { success: false, error: string }
11
10
  */
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.PROTOCOL_VERSION = void 0;
14
- exports.registerRpcHandlers = registerRpcHandlers;
15
- const model_resolver_js_1 = require("./model-resolver.js");
11
+ import { resolveModel } from "./model-resolver.js";
16
12
  /** RPC protocol version — bumped when the envelope or method contracts change. */
17
- exports.PROTOCOL_VERSION = 2;
13
+ export const PROTOCOL_VERSION = 2;
18
14
  /**
19
15
  * Wire a single RPC handler: listen on `channel`, run `fn(params)`,
20
16
  * emit the reply envelope on `channel:reply:${requestId}`.
@@ -40,10 +36,10 @@ function handleRpc(events, channel, fn) {
40
36
  * Register ping, spawn, and stop RPC handlers on the event bus.
41
37
  * Returns unsub functions for cleanup.
42
38
  */
43
- function registerRpcHandlers(deps) {
39
+ export function registerRpcHandlers(deps) {
44
40
  const { events, pi, getCtx, manager } = deps;
45
41
  const unsubPing = handleRpc(events, "subagents:rpc:ping", () => {
46
- return { version: exports.PROTOCOL_VERSION };
42
+ return { version: PROTOCOL_VERSION };
47
43
  });
48
44
  const unsubSpawn = handleRpc(events, "subagents:rpc:spawn", ({ type, prompt, options }) => {
49
45
  const ctx = getCtx();
@@ -61,7 +57,7 @@ function registerRpcHandlers(deps) {
61
57
  if (!registry) {
62
58
  throw new Error(`Model override "${normalizedOptions.model}" provided but ctx.modelRegistry is unavailable`);
63
59
  }
64
- const resolved = (0, model_resolver_js_1.resolveModel)(normalizedOptions.model, registry);
60
+ const resolved = resolveModel(normalizedOptions.model, registry);
65
61
  if (typeof resolved === "string") {
66
62
  // resolveModel returns a human-readable error string when the
67
63
  // input doesn't match any available model. Surface it instead of