lsd-pi 1.2.2 → 1.2.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.
Files changed (37) hide show
  1. package/dist/resources/extensions/slash-commands/plan.js +11 -7
  2. package/dist/resources/extensions/subagent/agents.js +19 -9
  3. package/dist/resources/extensions/subagent/index.js +112 -20
  4. package/dist/resources/extensions/subagent/launch-helpers.js +3 -2
  5. package/package.json +1 -1
  6. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  7. package/packages/pi-ai/dist/providers/anthropic-shared.js +11 -1
  8. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  9. package/packages/pi-ai/src/providers/anthropic-shared.ts +12 -1
  10. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +1 -0
  11. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  12. package/packages/pi-coding-agent/dist/core/agent-session.js +62 -6
  13. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  14. package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
  15. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  16. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +15 -0
  17. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  18. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  19. package/packages/pi-coding-agent/dist/core/skills.js +1 -0
  20. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  21. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  22. package/packages/pi-coding-agent/dist/core/system-prompt.js +1 -0
  23. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  24. package/packages/pi-coding-agent/dist/tests/path-display.test.js +1 -0
  25. package/packages/pi-coding-agent/dist/tests/path-display.test.js.map +1 -1
  26. package/packages/pi-coding-agent/package.json +1 -1
  27. package/packages/pi-coding-agent/src/core/agent-session.ts +60 -7
  28. package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
  29. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +18 -0
  30. package/packages/pi-coding-agent/src/core/skills.ts +1 -0
  31. package/packages/pi-coding-agent/src/core/system-prompt.ts +3 -0
  32. package/packages/pi-coding-agent/src/tests/path-display.test.ts +1 -0
  33. package/pkg/package.json +1 -1
  34. package/src/resources/extensions/slash-commands/plan.ts +14 -8
  35. package/src/resources/extensions/subagent/agents.ts +22 -7
  36. package/src/resources/extensions/subagent/index.ts +138 -18
  37. package/src/resources/extensions/subagent/launch-helpers.ts +2 -1
@@ -226,13 +226,17 @@ function restoreStateFromSession(ctx) {
226
226
  }
227
227
  async function enablePlanModeWithModelSwitch(pi, ctx, currentModel, next = {}) {
228
228
  enablePlanMode(pi, currentModel, next);
229
- // Signal that before_agent_start should switch to the reasoning model on next turn
229
+ // Keep fallback behavior in before_agent_start for restored sessions or when
230
+ // immediate switching cannot be completed at entry-time.
230
231
  reasoningModelSwitchDone = false;
231
232
  if (!readAutoSwitchPlanModelSetting())
232
233
  return;
233
- if (!readPlanModeReasoningModel()) {
234
+ const reasoningModel = parseQualifiedModelRef(readPlanModeReasoningModel());
235
+ if (!reasoningModel) {
234
236
  ctx.ui?.notify?.("OpusPlan: set a Plan reasoning model in /settings to auto-switch on entry", "info");
237
+ return;
235
238
  }
239
+ reasoningModelSwitchDone = await setModelIfNeeded(pi, ctx, reasoningModel);
236
240
  }
237
241
  function enablePlanMode(pi, currentModel, next = {}) {
238
242
  const currentMode = getPermissionMode();
@@ -267,14 +271,15 @@ function leavePlanMode(pi, approvalStatus, nextPermissionMode, clearTask = false
267
271
  }
268
272
  async function setModelIfNeeded(pi, ctx, modelRef) {
269
273
  if (!modelRef)
270
- return;
274
+ return false;
271
275
  const currentModel = parseQualifiedModelRef(ctx?.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined);
272
276
  if (sameModel(currentModel, modelRef))
273
- return;
277
+ return true;
274
278
  const model = resolveModelFromContext(ctx, modelRef);
275
279
  if (!model)
276
- return;
280
+ return false;
277
281
  await pi.setModel(model, { persist: false });
282
+ return true;
278
283
  }
279
284
  function buildExecutionKickoffMessage(options) {
280
285
  const { permissionMode, executeWithSubagent = false } = options;
@@ -531,8 +536,7 @@ export default function planCommand(pi) {
531
536
  if (!reasoningModelSwitchDone && readAutoSwitchPlanModelSetting()) {
532
537
  const reasoningModel = parseQualifiedModelRef(readPlanModeReasoningModel());
533
538
  if (reasoningModel) {
534
- reasoningModelSwitchDone = true;
535
- await setModelIfNeeded(pi, ctx, reasoningModel);
539
+ reasoningModelSwitchDone = await setModelIfNeeded(pi, ctx, reasoningModel);
536
540
  }
537
541
  }
538
542
  return { systemPrompt: buildPlanModeSystemPrompt() };
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import * as fs from "node:fs";
5
5
  import * as path from "node:path";
6
+ import { fileURLToPath } from "node:url";
6
7
  import { getAgentDir, parseFrontmatter } from "@gsd/pi-coding-agent";
7
8
  const PROJECT_AGENT_DIR_CANDIDATES = [".lsd", ".gsd", ".pi"];
8
9
  function normalizeAgentModel(model) {
@@ -50,7 +51,8 @@ function loadAgentsFromDir(dir, source) {
50
51
  const tools = frontmatter.tools
51
52
  ?.split(",")
52
53
  .map((t) => t.trim())
53
- .filter(Boolean);
54
+ .filter(Boolean)
55
+ .filter((tool, index, all) => all.indexOf(tool) === index);
54
56
  agents.push({
55
57
  name: frontmatter.name,
56
58
  description: frontmatter.description,
@@ -87,25 +89,33 @@ function findNearestProjectAgentsDir(cwd) {
87
89
  currentDir = parentDir;
88
90
  }
89
91
  }
92
+ function getBundledAgentsDir() {
93
+ const here = path.dirname(fileURLToPath(import.meta.url));
94
+ return path.resolve(here, "../../agents");
95
+ }
90
96
  export function discoverAgents(cwd, scope) {
91
97
  const userDir = path.join(getAgentDir(), "agents");
98
+ const bundledDir = getBundledAgentsDir();
92
99
  const projectAgentsDir = findNearestProjectAgentsDir(cwd);
100
+ const bundledAgents = scope === "project" ? [] : loadAgentsFromDir(bundledDir, "bundled");
93
101
  const userAgents = scope === "project" ? [] : loadAgentsFromDir(userDir, "user");
94
102
  const projectAgents = scope === "user" || !projectAgentsDir ? [] : loadAgentsFromDir(projectAgentsDir, "project");
95
103
  const agentMap = new Map();
96
- if (scope === "both") {
97
- for (const agent of userAgents)
98
- agentMap.set(agent.name, agent);
99
- for (const agent of projectAgents)
104
+ const addAgents = (items) => {
105
+ for (const agent of items)
100
106
  agentMap.set(agent.name, agent);
107
+ };
108
+ if (scope === "both") {
109
+ addAgents(bundledAgents);
110
+ addAgents(userAgents);
111
+ addAgents(projectAgents);
101
112
  }
102
113
  else if (scope === "user") {
103
- for (const agent of userAgents)
104
- agentMap.set(agent.name, agent);
114
+ addAgents(bundledAgents);
115
+ addAgents(userAgents);
105
116
  }
106
117
  else {
107
- for (const agent of projectAgents)
108
- agentMap.set(agent.name, agent);
118
+ addAgents(projectAgents);
109
119
  }
110
120
  return { agents: Array.from(agentMap.values()), projectAgentsDir };
111
121
  }
@@ -18,9 +18,9 @@ import * as os from "node:os";
18
18
  import * as path from "node:path";
19
19
  import { StringEnum } from "@gsd/pi-ai";
20
20
  import { getAgentDir, getMarkdownTheme, } from "@gsd/pi-coding-agent";
21
- import { Container, Markdown, Spacer, Text } from "@gsd/pi-tui";
21
+ import { Container, Key, Markdown, Spacer, Text } from "@gsd/pi-tui";
22
22
  import { Type } from "@sinclair/typebox";
23
- import { formatTokenCount } from "../shared/mod.js";
23
+ import { formatTokenCount, shortcutDesc } from "../shared/mod.js";
24
24
  import { discoverAgents } from "./agents.js";
25
25
  import { buildSubagentProcessArgs, getBundledExtensionPathsFromEnv } from "./launch-helpers.js";
26
26
  import { createIsolation, mergeDeltaPatches, readIsolationMode, } from "./isolation.js";
@@ -394,7 +394,7 @@ async function waitForFile(filePath, signal, timeoutMs = 30 * 60 * 1000) {
394
394
  }
395
395
  return false;
396
396
  }
397
- async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, modelOverride, parentModel, signal, onUpdate, makeDetails) {
397
+ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, modelOverride, parentModel, signal, onUpdate, makeDetails, foregroundHooks) {
398
398
  const agent = agents.find((a) => a.name === agentName);
399
399
  if (!agent) {
400
400
  const available = agents.map((a) => `"${a.name}"`).join(", ") || "none";
@@ -434,6 +434,28 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
434
434
  });
435
435
  }
436
436
  };
437
+ let wasAborted = false;
438
+ let deferTempPromptCleanup = false;
439
+ let tempPromptCleanupDone = false;
440
+ const cleanupTempPromptFiles = () => {
441
+ if (tempPromptCleanupDone)
442
+ return;
443
+ tempPromptCleanupDone = true;
444
+ if (tmpPromptPath)
445
+ try {
446
+ fs.unlinkSync(tmpPromptPath);
447
+ }
448
+ catch {
449
+ /* ignore */
450
+ }
451
+ if (tmpPromptDir)
452
+ try {
453
+ fs.rmdirSync(tmpPromptDir);
454
+ }
455
+ catch {
456
+ /* ignore */
457
+ }
458
+ };
437
459
  try {
438
460
  if (agent.systemPrompt.trim()) {
439
461
  const tmp = writePromptToTempFile(agent.name, agent.systemPrompt);
@@ -441,7 +463,6 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
441
463
  tmpPromptPath = tmp.filePath;
442
464
  }
443
465
  const args = buildSubagentProcessArgs(agent, task, tmpPromptPath, inferredModel);
444
- let wasAborted = false;
445
466
  const exitCode = await new Promise((resolve) => {
446
467
  const bundledPaths = getBundledExtensionPathsFromEnv();
447
468
  const extensionArgs = bundledPaths.flatMap((p) => ["--extension", p]);
@@ -459,6 +480,7 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
459
480
  let buffer = "";
460
481
  let completionSeen = false;
461
482
  let resolved = false;
483
+ let foregroundReleased = false;
462
484
  const procAbortController = new AbortController();
463
485
  let resolveBackgroundResult;
464
486
  let rejectBackgroundResult;
@@ -472,6 +494,27 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
472
494
  resolved = true;
473
495
  resolve(code);
474
496
  };
497
+ const adoptToBackground = (jobId) => {
498
+ if (resolved || foregroundReleased)
499
+ return false;
500
+ foregroundReleased = true;
501
+ deferTempPromptCleanup = true;
502
+ currentResult.backgroundJobId = jobId;
503
+ finishForeground(0);
504
+ return true;
505
+ };
506
+ backgroundResultPromise.finally(() => {
507
+ if (deferTempPromptCleanup)
508
+ cleanupTempPromptFiles();
509
+ });
510
+ foregroundHooks?.onStart?.({
511
+ agentName,
512
+ task,
513
+ cwd: cwd ?? defaultCwd,
514
+ abortController: procAbortController,
515
+ resultPromise: backgroundResultPromise,
516
+ adoptToBackground,
517
+ });
475
518
  proc.stdout.on("data", (data) => {
476
519
  buffer += data.toString();
477
520
  const lines = buffer.split("\n");
@@ -505,11 +548,13 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
505
548
  exitCode: finalExitCode,
506
549
  model: currentResult.model,
507
550
  });
551
+ foregroundHooks?.onFinish?.();
508
552
  finishForeground(finalExitCode);
509
553
  });
510
554
  proc.on("error", (error) => {
511
555
  liveSubagentProcesses.delete(proc);
512
556
  rejectBackgroundResult?.(error);
557
+ foregroundHooks?.onFinish?.();
513
558
  finishForeground(1);
514
559
  });
515
560
  const killProc = () => {
@@ -546,20 +591,8 @@ async function runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, mo
546
591
  return currentResult;
547
592
  }
548
593
  finally {
549
- if (tmpPromptPath)
550
- try {
551
- fs.unlinkSync(tmpPromptPath);
552
- }
553
- catch {
554
- /* ignore */
555
- }
556
- if (tmpPromptDir)
557
- try {
558
- fs.rmdirSync(tmpPromptDir);
559
- }
560
- catch {
561
- /* ignore */
562
- }
594
+ if (!deferTempPromptCleanup)
595
+ cleanupTempPromptFiles();
563
596
  }
564
597
  }
565
598
  const TaskItem = Type.Object({
@@ -610,6 +643,9 @@ const SubagentParams = Type.Object({
610
643
  });
611
644
  export default function (pi) {
612
645
  let bgManager = null;
646
+ const foregroundSubagentStatusKey = "foreground-subagent";
647
+ const foregroundSubagentHint = "Ctrl+B: move foreground subagent to background";
648
+ let activeForegroundSubagent = null;
613
649
  function getBgManager() {
614
650
  if (!bgManager)
615
651
  throw new Error("BackgroundJobManager not initialized.");
@@ -642,6 +678,7 @@ export default function (pi) {
642
678
  });
643
679
  });
644
680
  pi.on("session_before_switch", async () => {
681
+ activeForegroundSubagent = null;
645
682
  if (bgManager) {
646
683
  for (const job of bgManager.getRunningJobs()) {
647
684
  bgManager.cancel(job.id);
@@ -649,6 +686,7 @@ export default function (pi) {
649
686
  }
650
687
  });
651
688
  pi.on("session_shutdown", async () => {
689
+ activeForegroundSubagent = null;
652
690
  await stopLiveSubagents();
653
691
  if (bgManager) {
654
692
  bgManager.shutdown();
@@ -757,6 +795,38 @@ export default function (pi) {
757
795
  ctx.ui.notify(`Available agents (${discovery.agents.length}):\n${lines.join("\n")}`, "info");
758
796
  },
759
797
  });
798
+ pi.registerShortcut(Key.ctrl("b"), {
799
+ description: shortcutDesc("Move foreground subagent to background", "/subagents list"),
800
+ handler: async (ctx) => {
801
+ const running = activeForegroundSubagent;
802
+ if (!running || running.claimed)
803
+ return;
804
+ const manager = bgManager;
805
+ if (!manager) {
806
+ ctx.ui.notify("Background subagent manager is not available.", "error");
807
+ return;
808
+ }
809
+ running.claimed = true;
810
+ let jobId;
811
+ try {
812
+ jobId = manager.adoptRunning(running.agentName, running.task, running.cwd, running.abortController, running.resultPromise);
813
+ }
814
+ catch (error) {
815
+ running.claimed = false;
816
+ ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
817
+ return;
818
+ }
819
+ const released = running.adoptToBackground(jobId);
820
+ if (!released) {
821
+ running.claimed = false;
822
+ manager.cancel(jobId);
823
+ return;
824
+ }
825
+ activeForegroundSubagent = null;
826
+ ctx.ui.setStatus(foregroundSubagentStatusKey, undefined);
827
+ ctx.ui.notify(`Moved ${running.agentName} to background as ${jobId}. Use /subagents wait ${jobId}, /subagents output ${jobId}, or /subagents cancel ${jobId}.`, "info");
828
+ },
829
+ });
760
830
  pi.registerTool({
761
831
  name: "await_subagent",
762
832
  label: "Await Background Subagent",
@@ -785,13 +855,15 @@ export default function (pi) {
785
855
  "Model selection can be overridden per call, otherwise it is inferred from the agent config, delegated-task preferences, or the current session model.",
786
856
  "Modes: single ({ agent, task }), parallel ({ tasks: [{agent, task},...] }), chain ({ chain: [{agent, task},...] } with {previous} placeholder).",
787
857
  "Agents are defined as .md files in the configured user agent directory (for LSD this is typically ~/.lsd/agent/agents/) or project-local .lsd/agents/, with legacy support for .gsd/agents/ and .pi/agents/.",
858
+ "If the user asks for a named subagent such as scout, worker, reviewer, or planner, invoke this tool directly rather than the Skill tool.",
788
859
  "Use the /subagent command to list available agents and their descriptions.",
789
860
  "Set background: true (single mode only) to run detached — returns immediately with a sa_xxxx job ID. Completion is announced back into the session. Use await_subagent or /subagents to manage background jobs.",
790
861
  ].join(" "),
791
862
  promptGuidelines: [
792
863
  "Use subagent to delegate self-contained tasks that benefit from an isolated context window.",
793
- "When scout is the right fit, call the subagent tool directly do not type '/subagent' as a shell-like command.",
864
+ "The subagent tool is available directly as a tool call invoke it programmatically like any other tool, not via a slash command. Do NOT type '/scout' or '/subagent' in the chat; call this tool with the correct parameters instead.",
794
865
  "Valid call shapes: single mode uses { agent, task }, parallel mode uses { tasks: [{ agent, task }, ...] }, and chain mode uses { chain: [{ agent, task }, ...] }.",
866
+ "If the user names a subagent such as scout, worker, reviewer, or planner, use this subagent tool directly rather than the Skill tool or ad-hoc search.",
795
867
  "Recon planning rule: use no scout for narrow known-file work, one scout for one broad unfamiliar subsystem, and parallel scouts only when the work spans multiple loosely-coupled subsystems.",
796
868
  "Use scout only for broad or unfamiliar codebase reconnaissance before you read many files yourself; save direct reads for targeted lookups once the relevant files are known.",
797
869
  "Do not use scout as the reviewer, auditor, or final judge. Scout should map architecture, files, ownership, and likely hotspots for another agent or the parent model to evaluate.",
@@ -1045,7 +1117,24 @@ export default function (pi) {
1045
1117
  const taskId = crypto.randomUUID();
1046
1118
  isolation = await createIsolation(effectiveCwd, taskId, isolationMode);
1047
1119
  }
1048
- const result = await runSingleAgent(ctx.cwd, agents, params.agent, params.task, isolation ? isolation.workDir : params.cwd, undefined, params.model, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, signal, onUpdate, makeDetails("single"));
1120
+ const result = await runSingleAgent(ctx.cwd, agents, params.agent, params.task, isolation ? isolation.workDir : params.cwd, undefined, params.model, ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined, signal, onUpdate, makeDetails("single"), !isolation
1121
+ ? {
1122
+ onStart: (control) => {
1123
+ activeForegroundSubagent = { ...control, claimed: false };
1124
+ ctx.ui.setStatus(foregroundSubagentStatusKey, foregroundSubagentHint);
1125
+ },
1126
+ onFinish: () => {
1127
+ activeForegroundSubagent = null;
1128
+ ctx.ui.setStatus(foregroundSubagentStatusKey, undefined);
1129
+ },
1130
+ }
1131
+ : undefined);
1132
+ if (result.backgroundJobId) {
1133
+ return {
1134
+ content: [{ type: "text", text: `Moved ${result.agent} to background as **${result.backgroundJobId}**. Use \`await_subagent\`, \`/subagents wait ${result.backgroundJobId}\`, or \`/subagents output ${result.backgroundJobId}\`.` }],
1135
+ details: makeDetails("single")([result]),
1136
+ };
1137
+ }
1049
1138
  // Capture and merge delta if isolated
1050
1139
  if (isolation) {
1051
1140
  const patches = await isolation.captureDelta();
@@ -1197,6 +1286,9 @@ export default function (pi) {
1197
1286
  if (displayItems.length > COLLAPSED_ITEM_COUNT)
1198
1287
  text += `\n${theme.fg("muted", "(Ctrl+O to expand)")}`;
1199
1288
  }
1289
+ if (!isError && !r.backgroundJobId && !finalOutput) {
1290
+ text += `\n${theme.fg("muted", "Hint: Ctrl+B to move running foreground subagent to background")}`;
1291
+ }
1200
1292
  const usageStr = formatUsageStats(r.usage, r.model);
1201
1293
  if (usageStr)
1202
1294
  text += `\n${theme.fg("dim", usageStr)}`;
@@ -15,8 +15,9 @@ export function buildSubagentProcessArgs(agent, task, tmpPromptPath, model) {
15
15
  const args = ["--mode", "json", "-p", "--no-session"];
16
16
  if (model)
17
17
  args.push("--model", model);
18
- if (agent.tools && agent.tools.length > 0)
19
- args.push("--tools", agent.tools.join(","));
18
+ const uniqueTools = agent.tools?.filter((tool, index, all) => all.indexOf(tool) === index);
19
+ if (uniqueTools && uniqueTools.length > 0)
20
+ args.push("--tools", uniqueTools.join(","));
20
21
  if (tmpPromptPath)
21
22
  args.push("--append-system-prompt", tmpPromptPath);
22
23
  args.push(`Task: ${task}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lsd-pi",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "LSD — Looks Sort of Done coding agent",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic-shared.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic-shared.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"anthropic-shared.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic-shared.ts"],"names":[],"mappings":"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"}
@@ -323,7 +323,17 @@ export function convertMessages(messages, model, isOAuthToken, cacheControl) {
323
323
  export function convertTools(tools, isOAuthToken) {
324
324
  if (!tools)
325
325
  return [];
326
- return tools.map((tool) => {
326
+ const uniqueTools = [];
327
+ const seenToolNames = new Set();
328
+ for (const tool of tools) {
329
+ const mappedName = isOAuthToken ? toClaudeCodeName(tool.name) : tool.name;
330
+ if (seenToolNames.has(mappedName)) {
331
+ continue;
332
+ }
333
+ seenToolNames.add(mappedName);
334
+ uniqueTools.push(tool);
335
+ }
336
+ return uniqueTools.map((tool) => {
327
337
  const jsonSchema = tool.parameters;
328
338
  return {
329
339
  name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name,