pi-landstrip 0.18.23 → 0.18.24
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.ts +168 -90
- package/package.json +2 -2
package/dist/index.ts
CHANGED
|
@@ -80,6 +80,7 @@ import {
|
|
|
80
80
|
mkdirSync as mkdirSync3,
|
|
81
81
|
mkdtempSync,
|
|
82
82
|
readFileSync as readFileSync5,
|
|
83
|
+
readdirSync as readdirSync2,
|
|
83
84
|
readlinkSync,
|
|
84
85
|
realpathSync,
|
|
85
86
|
rmSync,
|
|
@@ -1605,7 +1606,6 @@ var INSPECTOR_BODY_LINES = 16;
|
|
|
1605
1606
|
var PI_THINKING_LEVELS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
1606
1607
|
var AGENTS_HELP_ROWS = [
|
|
1607
1608
|
["Tab", "Next tab"],
|
|
1608
|
-
["Shift+Tab / S", "Switch scope in Primary, Subagent, or Settings"],
|
|
1609
1609
|
["↑ / ↓", "Select item or scroll when follow is off"],
|
|
1610
1610
|
["F", "Toggle task log follow"],
|
|
1611
1611
|
["Page Up / Down", "Scroll task output by page"],
|
|
@@ -1618,7 +1618,7 @@ var AGENTS_HELP_ROWS = [
|
|
|
1618
1618
|
["E", "Edit project agent"],
|
|
1619
1619
|
["X", "Delete project agent"],
|
|
1620
1620
|
["Y / N", "Confirm or cancel deletion"],
|
|
1621
|
-
["Empty + Enter", "
|
|
1621
|
+
["Empty + Enter", "Inherit global setting"],
|
|
1622
1622
|
["Backspace", "Open parent task or edit setting"]
|
|
1623
1623
|
];
|
|
1624
1624
|
var MIN_SUPPORTED_PI_VERSION = [0, 82, 0];
|
|
@@ -1809,6 +1809,96 @@ function formatTaskUsageSummary(usage) {
|
|
|
1809
1809
|
parts.push(`$${usage.cost.toFixed(4)}`);
|
|
1810
1810
|
return parts.length > 0 ? parts.join(" ") : undefined;
|
|
1811
1811
|
}
|
|
1812
|
+
function findFilesRecursively(dir) {
|
|
1813
|
+
const results = [];
|
|
1814
|
+
try {
|
|
1815
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
1816
|
+
for (const entry of entries) {
|
|
1817
|
+
const fullPath = join6(dir, entry.name);
|
|
1818
|
+
if (entry.isDirectory()) {
|
|
1819
|
+
results.push(...findFilesRecursively(fullPath));
|
|
1820
|
+
} else if (entry.isFile()) {
|
|
1821
|
+
results.push(fullPath);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
} catch {}
|
|
1825
|
+
return results;
|
|
1826
|
+
}
|
|
1827
|
+
function extractCwdFromSessionFile(filePath) {
|
|
1828
|
+
try {
|
|
1829
|
+
const content = readFileSync5(filePath, "utf8");
|
|
1830
|
+
const firstNewline = content.indexOf(`
|
|
1831
|
+
`);
|
|
1832
|
+
const firstLine = firstNewline >= 0 ? content.slice(0, firstNewline) : content;
|
|
1833
|
+
if (!firstLine.trim())
|
|
1834
|
+
return;
|
|
1835
|
+
const header = JSON.parse(firstLine);
|
|
1836
|
+
if (typeof header.cwd === "string") {
|
|
1837
|
+
return header.cwd;
|
|
1838
|
+
}
|
|
1839
|
+
} catch {}
|
|
1840
|
+
return;
|
|
1841
|
+
}
|
|
1842
|
+
function extractCwdFromTaskJsonFile(filePath) {
|
|
1843
|
+
try {
|
|
1844
|
+
const content = readFileSync5(filePath, "utf8");
|
|
1845
|
+
const data = JSON.parse(content);
|
|
1846
|
+
return {
|
|
1847
|
+
cwd: typeof data.cwd === "string" ? data.cwd : undefined,
|
|
1848
|
+
parentSessionFile: typeof data.parentSessionFile === "string" ? data.parentSessionFile : undefined
|
|
1849
|
+
};
|
|
1850
|
+
} catch {
|
|
1851
|
+
return {};
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
function defaultSessionDirForCwd(cwd, agentDir = getAgentDir4()) {
|
|
1855
|
+
const resolvedCwd = resolve2(cwd);
|
|
1856
|
+
const safePath = `--${resolvedCwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
|
|
1857
|
+
return join6(agentDir, "sessions", safePath);
|
|
1858
|
+
}
|
|
1859
|
+
function isSubagentSessionDirForCwd(parentSessionDir, targetCwd) {
|
|
1860
|
+
const files = findFilesRecursively(parentSessionDir);
|
|
1861
|
+
if (files.length === 0) {
|
|
1862
|
+
return true;
|
|
1863
|
+
}
|
|
1864
|
+
const resolvedTarget = resolve2(targetCwd);
|
|
1865
|
+
const targetSessionDir = resolve2(defaultSessionDirForCwd(targetCwd));
|
|
1866
|
+
let hasTargetCwd = false;
|
|
1867
|
+
let hasOtherCwd = false;
|
|
1868
|
+
for (const file of files) {
|
|
1869
|
+
if (file.endsWith(".jsonl")) {
|
|
1870
|
+
const cwd = extractCwdFromSessionFile(file);
|
|
1871
|
+
if (cwd) {
|
|
1872
|
+
if (resolve2(cwd) === resolvedTarget) {
|
|
1873
|
+
hasTargetCwd = true;
|
|
1874
|
+
} else {
|
|
1875
|
+
hasOtherCwd = true;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
} else if (file.endsWith(".json")) {
|
|
1879
|
+
const { cwd, parentSessionFile } = extractCwdFromTaskJsonFile(file);
|
|
1880
|
+
if (cwd) {
|
|
1881
|
+
if (resolve2(cwd) === resolvedTarget) {
|
|
1882
|
+
hasTargetCwd = true;
|
|
1883
|
+
} else {
|
|
1884
|
+
hasOtherCwd = true;
|
|
1885
|
+
}
|
|
1886
|
+
} else if (parentSessionFile) {
|
|
1887
|
+
const resolvedParent = resolve2(parentSessionFile);
|
|
1888
|
+
if (resolvedParent.startsWith(targetSessionDir)) {
|
|
1889
|
+
hasTargetCwd = true;
|
|
1890
|
+
} else {
|
|
1891
|
+
hasOtherCwd = true;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
if (hasOtherCwd)
|
|
1897
|
+
return false;
|
|
1898
|
+
if (hasTargetCwd)
|
|
1899
|
+
return true;
|
|
1900
|
+
return true;
|
|
1901
|
+
}
|
|
1812
1902
|
function activeTaskRecords(tasks) {
|
|
1813
1903
|
const byId = new Map(tasks.map((task) => [task.id, task]));
|
|
1814
1904
|
const visibleIds = new Set;
|
|
@@ -2312,6 +2402,7 @@ class SubagentRuntime {
|
|
|
2312
2402
|
this.broker.reset();
|
|
2313
2403
|
this.restore(ctx);
|
|
2314
2404
|
await this.restorePrimaryAgent(ctx);
|
|
2405
|
+
await this.cleanupOrphanSubagentSessions(ctx);
|
|
2315
2406
|
const activeTools = this.pi.getActiveTools();
|
|
2316
2407
|
const withoutTask = activeTools.filter((tool) => tool !== "task");
|
|
2317
2408
|
const nextTools = this.maxSubagents > 0 ? [...withoutTask, "task"] : withoutTask;
|
|
@@ -2391,16 +2482,12 @@ ${this.primaryAgent.prompt}` };
|
|
|
2391
2482
|
const projectTrusted = isProjectTrusted(ctx);
|
|
2392
2483
|
let tasks = [...this.tasks.values()];
|
|
2393
2484
|
const requested = args.trim();
|
|
2394
|
-
let scope = projectTrusted ? "project" : "global";
|
|
2395
2485
|
let catalog = this.getAgentCatalog(ctx);
|
|
2396
2486
|
for (const diagnostic of catalog.diagnostics)
|
|
2397
2487
|
ctx.ui.notify(diagnostic, "warning");
|
|
2398
|
-
let globalCatalog = this.loadCatalog(ctx.cwd, getAgentDir4(), false);
|
|
2399
2488
|
let agents = [...catalog.agents.values()].filter((agent) => !agent.hidden).sort((left, right) => left.name.localeCompare(right.name));
|
|
2400
2489
|
let disabledOverrides = loadAgentDisabledOverrides(ctx.cwd, projectTrusted);
|
|
2401
2490
|
let maxSubagentsSettings = loadMaxSubagentsSettings(ctx.cwd, projectTrusted);
|
|
2402
|
-
const sandboxCallbacks = this.integration.sandboxCallbacks;
|
|
2403
|
-
let sandboxSettings = sandboxCallbacks?.load(ctx.cwd, projectTrusted) ?? { global: true };
|
|
2404
2491
|
let tab = requested ? "log" : "primary";
|
|
2405
2492
|
const agentsForTab = () => agents.filter((agent) => agentSupportsMode(agent, tab === "subagent" ? "subagent" : "primary"));
|
|
2406
2493
|
let selectedAgent = Math.max(0, agentsForTab().findIndex((agent) => agent.name === this.primaryAgent?.name));
|
|
@@ -2420,7 +2507,6 @@ ${this.primaryAgent.prompt}` };
|
|
|
2420
2507
|
const reloadAgents = () => {
|
|
2421
2508
|
const selectedName = agentsForTab()[selectedAgent]?.name;
|
|
2422
2509
|
catalog = this.getAgentCatalog(ctx);
|
|
2423
|
-
globalCatalog = this.loadCatalog(ctx.cwd, getAgentDir4(), false);
|
|
2424
2510
|
agents = [...catalog.agents.values()].filter((agent) => !agent.hidden).sort((left, right) => left.name.localeCompare(right.name));
|
|
2425
2511
|
disabledOverrides = loadAgentDisabledOverrides(ctx.cwd, projectTrusted);
|
|
2426
2512
|
const listedAgents = agentsForTab();
|
|
@@ -2429,7 +2515,6 @@ ${this.primaryAgent.prompt}` };
|
|
|
2429
2515
|
};
|
|
2430
2516
|
const reloadSettings = () => {
|
|
2431
2517
|
maxSubagentsSettings = loadMaxSubagentsSettings(ctx.cwd, projectTrusted);
|
|
2432
|
-
sandboxSettings = sandboxCallbacks?.load(ctx.cwd, projectTrusted) ?? { global: true };
|
|
2433
2518
|
};
|
|
2434
2519
|
const refreshTasks = () => {
|
|
2435
2520
|
const selectedId = tasks[selectedTask]?.id;
|
|
@@ -2457,11 +2542,7 @@ ${this.primaryAgent.prompt}` };
|
|
|
2457
2542
|
this.pi.registerTool(this.createTaskTool(undefined, this.primaryRules, ctx));
|
|
2458
2543
|
}
|
|
2459
2544
|
};
|
|
2460
|
-
const
|
|
2461
|
-
const selectedMaxSubagents = () => scope === "global" ? maxSubagentsSettings.global : maxSubagentsSettings.project ?? maxSubagentsSettings.global;
|
|
2462
|
-
const settingField = (setting) => setting === 0 ? "maxSubagents" : "sandboxEnabled";
|
|
2463
|
-
const settingLabel = (settingScope, field) => `${settingScope === "global" ? "Global" : "Project"} ${field}`;
|
|
2464
|
-
const selectedSandboxEnabled = () => scope === "global" ? sandboxSettings.global : sandboxSettings.project ?? sandboxSettings.global;
|
|
2545
|
+
const selectedMaxSubagents = () => maxSubagentsSettings.project ?? maxSubagentsSettings.global;
|
|
2465
2546
|
await ctx.ui.custom((tui, theme, _keybindings, done) => ({
|
|
2466
2547
|
render: (width) => {
|
|
2467
2548
|
const contentWidth = Math.max(1, width - 4);
|
|
@@ -2475,7 +2556,7 @@ ${this.primaryAgent.prompt}` };
|
|
|
2475
2556
|
return `${clipped}${" ".repeat(Math.max(0, cellWidth - visibleWidth2(clipped)))}`;
|
|
2476
2557
|
};
|
|
2477
2558
|
refreshTasks();
|
|
2478
|
-
const tabs =
|
|
2559
|
+
const tabs = dialogTabs(theme, ["Primary", "Subagent", "Tasks", "Log", "Settings", "Help"], `${tab[0]?.toUpperCase()}${tab.slice(1)}`);
|
|
2479
2560
|
if (tab === "primary" || tab === "subagent") {
|
|
2480
2561
|
const listedAgents = agentsForTab();
|
|
2481
2562
|
const start = Math.max(0, Math.min(selectedAgent - 3, listedAgents.length - 7));
|
|
@@ -2494,17 +2575,14 @@ ${this.primaryAgent.prompt}` };
|
|
|
2494
2575
|
const index = start + offset;
|
|
2495
2576
|
const selected = index === selectedAgent;
|
|
2496
2577
|
const cursor = selected ? theme.fg("accent", "›") : " ";
|
|
2497
|
-
const current = scopedAgent(agent2);
|
|
2498
|
-
const unavailable = current === undefined;
|
|
2499
|
-
const scopedDisabled = current?.disabled ?? false;
|
|
2500
2578
|
const disabled = agent2.disabled;
|
|
2501
2579
|
const deleting = confirmingDeleteAgent === agent2.name;
|
|
2502
|
-
const inherited =
|
|
2503
|
-
const state =
|
|
2580
|
+
const inherited = !disabledOverrides.project.has(agent2.name);
|
|
2581
|
+
const state = inherited ? `inherited ${disabled ? "off" : "on"}` : disabled ? "disabled" : "enabled";
|
|
2504
2582
|
const color = deleting ? "error" : disabled ? "muted" : "text";
|
|
2505
2583
|
const plainName = pad(`@${agent2.name}`, nameWidth);
|
|
2506
2584
|
const name = deleting ? theme.fg("error", plainName) : disabled ? theme.fg("muted", plainName) : colorizeAgentText(agent2.color, plainName, (agentColor, text) => theme.fg(agentColor, text));
|
|
2507
|
-
const line = `${cursor} ${name} ${theme.fg(color, pad(agent2.source, sourceWidth))} ${theme.fg(color, pad(agent2.model ?? "current model", modelWidth))} ${theme.fg(deleting ? "error" :
|
|
2585
|
+
const line = `${cursor} ${name} ${theme.fg(color, pad(agent2.source, sourceWidth))} ${theme.fg(color, pad(agent2.model ?? "current model", modelWidth))} ${theme.fg(deleting ? "error" : disabled ? "warning" : color, pad(state, stateWidth))}`;
|
|
2508
2586
|
lines2.push(agent2.name === this.primaryAgent?.name ? theme.bold(line) : line);
|
|
2509
2587
|
}
|
|
2510
2588
|
if (listedAgents.length === 0) {
|
|
@@ -2555,26 +2633,19 @@ ${this.primaryAgent.prompt}` };
|
|
|
2555
2633
|
return box(lines2);
|
|
2556
2634
|
}
|
|
2557
2635
|
if (tab === "settings") {
|
|
2558
|
-
const maxSubagentsInherited =
|
|
2559
|
-
const sandboxInherited = scope === "project" && sandboxSettings.project === undefined;
|
|
2636
|
+
const maxSubagentsInherited = maxSubagentsSettings.project === undefined;
|
|
2560
2637
|
const rows = [
|
|
2561
2638
|
{
|
|
2562
2639
|
label: "maxSubagents",
|
|
2563
2640
|
value: String(selectedMaxSubagents()),
|
|
2564
2641
|
inherited: maxSubagentsInherited,
|
|
2565
2642
|
unavailable: false
|
|
2566
|
-
},
|
|
2567
|
-
{
|
|
2568
|
-
label: "sandboxEnabled",
|
|
2569
|
-
value: selectedSandboxEnabled() ? "on" : "off",
|
|
2570
|
-
inherited: sandboxInherited,
|
|
2571
|
-
unavailable: sandboxCallbacks === undefined
|
|
2572
2643
|
}
|
|
2573
2644
|
];
|
|
2574
2645
|
const lines2 = [tabs, ""];
|
|
2575
2646
|
if (settingEditor) {
|
|
2576
|
-
const current =
|
|
2577
|
-
lines2.push(theme.fg("dim", `
|
|
2647
|
+
const current = String(selectedMaxSubagents());
|
|
2648
|
+
lines2.push(theme.fg("dim", ` Project maxSubagents · current ${current}`), "", ` ${theme.fg("accent", "›")} [ ${settingEditor.value}${theme.fg("accent", "█")} ]`, "", theme.fg("dim", " empty inherit · enter submit · esc cancel"));
|
|
2578
2649
|
if (saving)
|
|
2579
2650
|
lines2.push("", theme.fg("dim", "Saving…"));
|
|
2580
2651
|
return box(lines2);
|
|
@@ -2587,9 +2658,6 @@ ${this.primaryAgent.prompt}` };
|
|
|
2587
2658
|
const label = theme.fg(row.unavailable ? "muted" : "text", row.label);
|
|
2588
2659
|
lines2.push(`${cursor} ${value} ${label}`);
|
|
2589
2660
|
}
|
|
2590
|
-
if (selectedSetting === 1) {
|
|
2591
|
-
lines2.push("", theme.fg("dim", rows[1]?.inherited ? "Controls OS sandboxing. Use /sandbox to inspect its policy. Using the Global value." : "Controls OS sandboxing. Use /sandbox to inspect its policy."));
|
|
2592
|
-
}
|
|
2593
2661
|
if (saving)
|
|
2594
2662
|
lines2.push("", theme.fg("dim", "Saving…"));
|
|
2595
2663
|
return box(lines2);
|
|
@@ -2693,19 +2761,6 @@ ${this.primaryAgent.prompt}` };
|
|
|
2693
2761
|
}
|
|
2694
2762
|
return;
|
|
2695
2763
|
}
|
|
2696
|
-
if ((matchesKey(data, "shift+tab") || data.toLowerCase() === "s") && (tab === "primary" || tab === "subagent" || tab === "settings") && settingEditor === undefined) {
|
|
2697
|
-
if (saving)
|
|
2698
|
-
return;
|
|
2699
|
-
if (!projectTrusted && scope === "global") {
|
|
2700
|
-
ctx.ui.notify("Project settings require a trusted project", "warning");
|
|
2701
|
-
return;
|
|
2702
|
-
}
|
|
2703
|
-
scope = scope === "project" ? "global" : "project";
|
|
2704
|
-
reloadAgents();
|
|
2705
|
-
reloadSettings();
|
|
2706
|
-
tui.requestRender();
|
|
2707
|
-
return;
|
|
2708
|
-
}
|
|
2709
2764
|
if (matchesKey(data, "tab")) {
|
|
2710
2765
|
if (settingEditor !== undefined)
|
|
2711
2766
|
return;
|
|
@@ -2765,22 +2820,25 @@ ${this.primaryAgent.prompt}` };
|
|
|
2765
2820
|
});
|
|
2766
2821
|
return;
|
|
2767
2822
|
} else if (data === " " && agent && !saving) {
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
ctx.ui.notify("Local-only agents are unavailable in Global scope", "warning");
|
|
2823
|
+
if (!projectTrusted) {
|
|
2824
|
+
ctx.ui.notify("Project settings require a trusted project", "warning");
|
|
2771
2825
|
return;
|
|
2772
2826
|
}
|
|
2773
|
-
const disabled = !
|
|
2827
|
+
const disabled = !agent.disabled;
|
|
2774
2828
|
saving = true;
|
|
2775
|
-
setAgentDisabledForScope(ctx.cwd, agent.name, disabled,
|
|
2829
|
+
setAgentDisabledForScope(ctx.cwd, agent.name, disabled, "project").then(async () => {
|
|
2776
2830
|
await refreshAgentRuntime(agent.name);
|
|
2777
|
-
ctx.ui.notify(`${agent.name} ${disabled ? "disabled" : "enabled"} in
|
|
2831
|
+
ctx.ui.notify(`${agent.name} ${disabled ? "disabled" : "enabled"} in project settings`, "info");
|
|
2778
2832
|
}).catch((error) => ctx.ui.notify(`Could not update agent: ${formatError(error)}`, "error")).finally(() => {
|
|
2779
2833
|
saving = false;
|
|
2780
2834
|
tui.requestRender();
|
|
2781
2835
|
});
|
|
2782
2836
|
return;
|
|
2783
|
-
} else if (data.toLowerCase() === "i" &&
|
|
2837
|
+
} else if (data.toLowerCase() === "i" && agent && !saving) {
|
|
2838
|
+
if (!projectTrusted) {
|
|
2839
|
+
ctx.ui.notify("Project settings require a trusted project", "warning");
|
|
2840
|
+
return;
|
|
2841
|
+
}
|
|
2784
2842
|
if (!disabledOverrides.project.has(agent.name))
|
|
2785
2843
|
return;
|
|
2786
2844
|
saving = true;
|
|
@@ -2822,19 +2880,21 @@ ${this.primaryAgent.prompt}` };
|
|
|
2822
2880
|
return;
|
|
2823
2881
|
}
|
|
2824
2882
|
if (matchesKey(data, "return")) {
|
|
2825
|
-
const
|
|
2826
|
-
const input = editor.value.trim();
|
|
2883
|
+
const input = settingEditor.value.trim();
|
|
2827
2884
|
let save;
|
|
2828
2885
|
let notifyMessage;
|
|
2829
2886
|
if (input === "") {
|
|
2830
|
-
if (
|
|
2831
|
-
|
|
2832
|
-
|
|
2887
|
+
if (!projectTrusted) {
|
|
2888
|
+
ctx.ui.notify("Project settings require a trusted project", "warning");
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
save = clearMaxSubagentsConfigForScope(ctx.cwd, "project");
|
|
2892
|
+
notifyMessage = "Project maxSubagents inherits Global";
|
|
2893
|
+
} else {
|
|
2894
|
+
if (!projectTrusted) {
|
|
2895
|
+
ctx.ui.notify("Project settings require a trusted project", "warning");
|
|
2833
2896
|
return;
|
|
2834
2897
|
}
|
|
2835
|
-
save = editor.setting === 0 ? clearMaxSubagentsConfigForScope(ctx.cwd, "project") : sandboxCallbacks?.clearProject(ctx);
|
|
2836
|
-
notifyMessage = `${settingLabel(editor.scope, editor.field)} inherits Global`;
|
|
2837
|
-
} else if (editor.setting === 0) {
|
|
2838
2898
|
if (!/^\d+$/.test(input)) {
|
|
2839
2899
|
ctx.ui.notify(`Enter a whole number between 0 and ${MAX_SUBAGENTS}`, "error");
|
|
2840
2900
|
return;
|
|
@@ -2844,21 +2904,8 @@ ${this.primaryAgent.prompt}` };
|
|
|
2844
2904
|
ctx.ui.notify(`Enter a whole number between 0 and ${MAX_SUBAGENTS}`, "error");
|
|
2845
2905
|
return;
|
|
2846
2906
|
}
|
|
2847
|
-
save = setMaxSubagentsConfigForScope(ctx.cwd, parsed,
|
|
2848
|
-
notifyMessage =
|
|
2849
|
-
} else {
|
|
2850
|
-
const normalized = input.toLowerCase();
|
|
2851
|
-
const parsed = ["1", "on", "true", "yes"].includes(normalized) ? true : ["0", "off", "false", "no"].includes(normalized) ? false : undefined;
|
|
2852
|
-
if (parsed === undefined) {
|
|
2853
|
-
ctx.ui.notify("Enter on/off, true/false, or 1/0", "error");
|
|
2854
|
-
return;
|
|
2855
|
-
}
|
|
2856
|
-
save = sandboxCallbacks?.setEnabled(ctx, parsed, editor.scope);
|
|
2857
|
-
notifyMessage = `${settingLabel(editor.scope, editor.field)} = ${parsed ? "on" : "off"}`;
|
|
2858
|
-
}
|
|
2859
|
-
if (!save) {
|
|
2860
|
-
ctx.ui.notify("Sandbox settings are unavailable", "warning");
|
|
2861
|
-
return;
|
|
2907
|
+
save = setMaxSubagentsConfigForScope(ctx.cwd, parsed, "project");
|
|
2908
|
+
notifyMessage = `Project maxSubagents = ${parsed}`;
|
|
2862
2909
|
}
|
|
2863
2910
|
saving = true;
|
|
2864
2911
|
settingEditor = undefined;
|
|
@@ -2868,9 +2915,6 @@ ${this.primaryAgent.prompt}` };
|
|
|
2868
2915
|
const loadedMaxSubagents = loadMaxSubagentsSettings(ctx.cwd, projectTrusted);
|
|
2869
2916
|
this.setMaxSubagents(loadedMaxSubagents.project ?? loadedMaxSubagents.global);
|
|
2870
2917
|
maxSubagentsSettings = loadedMaxSubagents;
|
|
2871
|
-
sandboxSettings = sandboxCallbacks?.load(ctx.cwd, projectTrusted) ?? {
|
|
2872
|
-
global: true
|
|
2873
|
-
};
|
|
2874
2918
|
ctx.ui.notify(notifyMessage ?? "Setting updated", "info");
|
|
2875
2919
|
}).catch((error) => ctx.ui.notify(`Could not save setting: ${formatError(error)}`, "error")).finally(() => {
|
|
2876
2920
|
saving = false;
|
|
@@ -2882,9 +2926,7 @@ ${this.primaryAgent.prompt}` };
|
|
|
2882
2926
|
const printable = kittyChar ?? (data.length === 1 && !isControlChar(data) ? data : undefined);
|
|
2883
2927
|
if (printable === undefined)
|
|
2884
2928
|
return;
|
|
2885
|
-
if (
|
|
2886
|
-
return;
|
|
2887
|
-
if (settingEditor.setting === 1 && !/^[a-zA-Z0-9]$/.test(printable))
|
|
2929
|
+
if (!/^\d$/.test(printable))
|
|
2888
2930
|
return;
|
|
2889
2931
|
settingEditor.value += printable;
|
|
2890
2932
|
tui.requestRender();
|
|
@@ -2895,19 +2937,16 @@ ${this.primaryAgent.prompt}` };
|
|
|
2895
2937
|
return;
|
|
2896
2938
|
}
|
|
2897
2939
|
if (matchesKey(data, "up"))
|
|
2898
|
-
selectedSetting =
|
|
2940
|
+
selectedSetting = 0;
|
|
2899
2941
|
else if (matchesKey(data, "down"))
|
|
2900
|
-
selectedSetting =
|
|
2942
|
+
selectedSetting = 0;
|
|
2901
2943
|
else if (matchesKey(data, "return")) {
|
|
2902
|
-
if (
|
|
2903
|
-
ctx.ui.notify("
|
|
2944
|
+
if (!projectTrusted) {
|
|
2945
|
+
ctx.ui.notify("Project settings require a trusted project", "warning");
|
|
2904
2946
|
return;
|
|
2905
2947
|
}
|
|
2906
2948
|
settingEditor = {
|
|
2907
|
-
|
|
2908
|
-
scope,
|
|
2909
|
-
field: settingField(selectedSetting),
|
|
2910
|
-
value: ""
|
|
2949
|
+
value: maxSubagentsSettings.project !== undefined ? String(maxSubagentsSettings.project) : ""
|
|
2911
2950
|
};
|
|
2912
2951
|
} else
|
|
2913
2952
|
return;
|
|
@@ -3827,6 +3866,9 @@ ${renderTaskResult(task.id, "error", message)}`);
|
|
|
3827
3866
|
task.deleted = true;
|
|
3828
3867
|
task.delivered = true;
|
|
3829
3868
|
this.controllers.get(taskId)?.abort();
|
|
3869
|
+
if (task.sessionDir && existsSync4(task.sessionDir)) {
|
|
3870
|
+
rmSync(task.sessionDir, { recursive: true, force: true });
|
|
3871
|
+
}
|
|
3830
3872
|
this.tasks.delete(taskId);
|
|
3831
3873
|
this.pendingPrompts.delete(taskId);
|
|
3832
3874
|
this.foregroundClaims.delete(taskId);
|
|
@@ -3837,6 +3879,42 @@ ${renderTaskResult(task.id, "error", message)}`);
|
|
|
3837
3879
|
this.updateTaskWidget(ctx);
|
|
3838
3880
|
return deleted;
|
|
3839
3881
|
}
|
|
3882
|
+
async cleanupOrphanSubagentSessions(ctx) {
|
|
3883
|
+
try {
|
|
3884
|
+
const subagentBaseDir = join6(getAgentDir4(), "sessions", "pi-landstrip");
|
|
3885
|
+
if (!existsSync4(subagentBaseDir))
|
|
3886
|
+
return;
|
|
3887
|
+
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
3888
|
+
const sessionDir = sessionFile ? dirname3(sessionFile) : undefined;
|
|
3889
|
+
const cwdSessions = sessionDir ? await SessionManager.list(ctx.cwd, sessionDir).catch(() => []) : await SessionManager.list(ctx.cwd).catch(() => []);
|
|
3890
|
+
const allSessions = await SessionManager.listAll().catch(() => []);
|
|
3891
|
+
const existingParentSessionIds = new Set;
|
|
3892
|
+
for (const s of cwdSessions) {
|
|
3893
|
+
if (s.id)
|
|
3894
|
+
existingParentSessionIds.add(s.id);
|
|
3895
|
+
}
|
|
3896
|
+
for (const s of allSessions) {
|
|
3897
|
+
if (s.id)
|
|
3898
|
+
existingParentSessionIds.add(s.id);
|
|
3899
|
+
}
|
|
3900
|
+
const activeId = ctx.sessionManager.getSessionId();
|
|
3901
|
+
if (activeId)
|
|
3902
|
+
existingParentSessionIds.add(activeId);
|
|
3903
|
+
const entries = readdirSync2(subagentBaseDir, { withFileTypes: true });
|
|
3904
|
+
const targetCwd = ctx.cwd;
|
|
3905
|
+
for (const entry of entries) {
|
|
3906
|
+
if (!entry.isDirectory())
|
|
3907
|
+
continue;
|
|
3908
|
+
const parentSessionId = entry.name;
|
|
3909
|
+
if (existingParentSessionIds.has(parentSessionId))
|
|
3910
|
+
continue;
|
|
3911
|
+
const parentSessionDir = join6(subagentBaseDir, parentSessionId);
|
|
3912
|
+
if (isSubagentSessionDirForCwd(parentSessionDir, targetCwd)) {
|
|
3913
|
+
rmSync(parentSessionDir, { recursive: true, force: true });
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
} catch {}
|
|
3917
|
+
}
|
|
3840
3918
|
restore(ctx) {
|
|
3841
3919
|
this.tasks.clear();
|
|
3842
3920
|
for (const entry of ctx.sessionManager.getBranch()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-landstrip",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.24",
|
|
4
4
|
"description": "Sandboxed Bash and process-backed agents for Pi",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"landstrip",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"ci:test": "npm run test"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@landstrip/landstrip": "^0.18.
|
|
42
|
+
"@landstrip/landstrip": "^0.18.24",
|
|
43
43
|
"jsonc-parser": "^3.3.1",
|
|
44
44
|
"minimatch": "^10.2.5",
|
|
45
45
|
"yaml": "^2.9.0"
|