@oh-my-pi/pi-coding-agent 13.2.0 → 13.3.0
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 +54 -1
- package/package.json +7 -7
- package/scripts/format-prompts.ts +33 -14
- package/scripts/generate-docs-index.ts +2 -2
- package/src/capability/index.ts +1 -2
- package/src/cli/args.ts +3 -3
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/file-processor.ts +1 -2
- package/src/cli/grep-cli.ts +1 -1
- package/src/cli/jupyter-cli.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli/shell-cli.ts +1 -1
- package/src/cli/ssh-cli.ts +1 -1
- package/src/cli/stats-cli.ts +1 -2
- package/src/cli/update-cli.ts +1 -2
- package/src/cli/web-search-cli.ts +1 -1
- package/src/cli.ts +1 -1
- package/src/commands/launch.ts +2 -1
- package/src/commit/agentic/agent.ts +2 -1
- package/src/commit/agentic/index.ts +1 -2
- package/src/commit/agentic/prompts/system.md +3 -3
- package/src/commit/agentic/tools/propose-changelog.ts +30 -19
- package/src/commit/changelog/generate.ts +16 -6
- package/src/commit/changelog/index.ts +2 -1
- package/src/commit/pipeline.ts +1 -2
- package/src/commit/prompts/reduce-system.md +1 -1
- package/src/commit/types.ts +10 -1
- package/src/config/keybindings.ts +1 -2
- package/src/config/model-registry.ts +1 -1
- package/src/config/prompt-templates.ts +14 -2
- package/src/config/settings-schema.ts +36 -4
- package/src/config/settings.ts +19 -2
- package/src/config.ts +1 -2
- package/src/debug/index.ts +1 -1
- package/src/debug/report-bundle.ts +1 -2
- package/src/debug/system-info.ts +1 -2
- package/src/discovery/agents.ts +2 -2
- package/src/discovery/builtin.ts +8 -9
- package/src/discovery/claude-plugins.ts +2 -2
- package/src/discovery/claude.ts +30 -12
- package/src/discovery/codex.ts +3 -3
- package/src/discovery/cursor.ts +5 -4
- package/src/discovery/gemini.ts +5 -5
- package/src/discovery/helpers.ts +47 -69
- package/src/discovery/mcp-json.ts +3 -3
- package/src/discovery/opencode.ts +7 -8
- package/src/discovery/ssh.ts +3 -3
- package/src/discovery/vscode.ts +3 -2
- package/src/discovery/windsurf.ts +3 -2
- package/src/exa/company.ts +1 -1
- package/src/exa/factory.ts +1 -6
- package/src/exa/linkedin.ts +1 -1
- package/src/exa/mcp-client.ts +19 -8
- package/src/exa/search.ts +2 -2
- package/src/exa/types.ts +3 -3
- package/src/exec/bash-executor.ts +2 -1
- package/src/exec/non-interactive-env.ts +43 -0
- package/src/export/custom-share.ts +1 -1
- package/src/export/html/index.ts +1 -2
- package/src/extensibility/custom-commands/loader.ts +1 -2
- package/src/extensibility/plugins/installer.ts +1 -2
- package/src/extensibility/plugins/loader.ts +1 -2
- package/src/extensibility/plugins/manager.ts +3 -2
- package/src/extensibility/skills.ts +59 -115
- package/src/index.ts +1 -3
- package/src/internal-urls/docs-index.generated.ts +1 -1
- package/src/ipy/executor.ts +1 -2
- package/src/ipy/gateway-coordinator.ts +1 -2
- package/src/ipy/modules.ts +1 -1
- package/src/ipy/runtime.ts +2 -3
- package/src/main.ts +1 -2
- package/src/mcp/config.ts +2 -2
- package/src/mcp/transports/stdio.ts +1 -2
- package/src/memories/index.ts +1 -2
- package/src/modes/components/extensions/extension-dashboard.ts +1 -1
- package/src/modes/components/extensions/inspector-panel.ts +8 -2
- package/src/modes/components/footer.ts +1 -2
- package/src/modes/components/settings-defs.ts +17 -1
- package/src/modes/components/status-line/segments.ts +1 -2
- package/src/modes/components/status-line.ts +7 -5
- package/src/modes/components/tool-execution.ts +3 -10
- package/src/modes/components/welcome.ts +1 -1
- package/src/modes/controllers/command-controller.ts +1 -2
- package/src/modes/controllers/mcp-command-controller.ts +5 -4
- package/src/modes/controllers/selector-controller.ts +22 -1
- package/src/modes/controllers/ssh-command-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +11 -3
- package/src/modes/oauth-manual-input.ts +42 -0
- package/src/modes/shared.ts +1 -2
- package/src/modes/theme/theme.ts +1 -2
- package/src/modes/types.ts +2 -0
- package/src/patch/hashline.ts +19 -1
- package/src/patch/index.ts +1 -25
- package/src/prompts/agents/designer.md +7 -10
- package/src/prompts/agents/explore.md +15 -23
- package/src/prompts/agents/init.md +23 -23
- package/src/prompts/agents/plan.md +14 -77
- package/src/prompts/agents/reviewer.md +6 -5
- package/src/prompts/agents/task.md +13 -11
- package/src/prompts/compaction/branch-summary.md +3 -3
- package/src/prompts/compaction/compaction-short-summary.md +7 -7
- package/src/prompts/compaction/compaction-summary-context.md +1 -1
- package/src/prompts/compaction/compaction-summary.md +5 -5
- package/src/prompts/compaction/compaction-turn-prefix.md +3 -3
- package/src/prompts/compaction/compaction-update-summary.md +11 -11
- package/src/prompts/memories/consolidation.md +5 -5
- package/src/prompts/memories/read-path.md +6 -6
- package/src/prompts/memories/stage_one_input.md +1 -1
- package/src/prompts/memories/stage_one_system.md +5 -5
- package/src/prompts/review-request.md +4 -4
- package/src/prompts/system/agent-creation-architect.md +17 -17
- package/src/prompts/system/agent-creation-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +2 -0
- package/src/prompts/system/custom-system-prompt.md +4 -4
- package/src/prompts/system/plan-mode-active.md +20 -20
- package/src/prompts/system/plan-mode-approved.md +7 -7
- package/src/prompts/system/plan-mode-reference.md +2 -2
- package/src/prompts/system/plan-mode-subagent.md +8 -8
- package/src/prompts/system/subagent-submit-reminder.md +5 -5
- package/src/prompts/system/subagent-system-prompt.md +29 -22
- package/src/prompts/system/subagent-user-prompt.md +7 -3
- package/src/prompts/system/summarization-system.md +1 -1
- package/src/prompts/system/system-prompt.md +214 -226
- package/src/prompts/system/title-system.md +2 -2
- package/src/prompts/system/ttsr-interrupt.md +1 -1
- package/src/prompts/system/web-search.md +16 -16
- package/src/prompts/tools/ask.md +1 -3
- package/src/prompts/tools/await.md +2 -4
- package/src/prompts/tools/bash.md +5 -7
- package/src/prompts/tools/browser.md +4 -6
- package/src/prompts/tools/calculator.md +1 -3
- package/src/prompts/tools/cancel-job.md +2 -4
- package/src/prompts/tools/exit-plan-mode.md +7 -7
- package/src/prompts/tools/fetch.md +0 -2
- package/src/prompts/tools/find.md +3 -5
- package/src/prompts/tools/gemini-image.md +6 -22
- package/src/prompts/tools/grep.md +4 -6
- package/src/prompts/tools/hashline.md +56 -15
- package/src/prompts/tools/lsp.md +1 -3
- package/src/prompts/tools/patch.md +7 -9
- package/src/prompts/tools/python.md +10 -14
- package/src/prompts/tools/read.md +0 -2
- package/src/prompts/tools/replace.md +5 -7
- package/src/prompts/tools/ssh.md +3 -5
- package/src/prompts/tools/task-summary.md +4 -4
- package/src/prompts/tools/task.md +7 -9
- package/src/prompts/tools/todo-write.md +7 -9
- package/src/prompts/tools/web-search.md +3 -5
- package/src/prompts/tools/write.md +3 -5
- package/src/sdk.ts +4 -2
- package/src/session/agent-session.ts +10 -26
- package/src/session/agent-storage.ts +1 -2
- package/src/session/history-storage.ts +1 -2
- package/src/session/session-manager.ts +10 -2
- package/src/slash-commands/builtin-registry.ts +26 -1
- package/src/ssh/connection-manager.ts +11 -2
- package/src/ssh/sshfs-mount.ts +7 -1
- package/src/system-prompt.ts +29 -103
- package/src/task/agents.ts +1 -1
- package/src/task/index.ts +211 -70
- package/src/task/render.ts +24 -8
- package/src/task/types.ts +6 -1
- package/src/task/worktree.ts +394 -32
- package/src/tools/ask.ts +0 -1
- package/src/tools/bash-interactive.ts +2 -45
- package/src/tools/bash.ts +5 -5
- package/src/tools/browser.ts +1 -2
- package/src/tools/gemini-image.ts +8 -28
- package/src/tools/json-tree.ts +2 -1
- package/src/tools/python.ts +1 -1
- package/src/tools/read.ts +1 -2
- package/src/tools/submit-result.ts +22 -23
- package/src/utils/commit-message-generator.ts +132 -0
- package/src/utils/tools-manager.ts +1 -2
- package/src/web/scrapers/artifacthub.ts +2 -1
- package/src/web/scrapers/aur.ts +2 -1
- package/src/web/scrapers/biorxiv.ts +2 -1
- package/src/web/scrapers/bluesky.ts +2 -1
- package/src/web/scrapers/chocolatey.ts +2 -1
- package/src/web/scrapers/cisa-kev.ts +2 -1
- package/src/web/scrapers/clojars.ts +2 -1
- package/src/web/scrapers/coingecko.ts +2 -1
- package/src/web/scrapers/crates-io.ts +2 -1
- package/src/web/scrapers/crossref.ts +2 -1
- package/src/web/scrapers/discogs.ts +3 -1
- package/src/web/scrapers/discourse.ts +2 -1
- package/src/web/scrapers/dockerhub.ts +2 -1
- package/src/web/scrapers/fdroid.ts +2 -1
- package/src/web/scrapers/firefox-addons.ts +2 -1
- package/src/web/scrapers/flathub.ts +2 -1
- package/src/web/scrapers/gitlab.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +2 -1
- package/src/web/scrapers/hackage.ts +2 -1
- package/src/web/scrapers/hackernews.ts +2 -1
- package/src/web/scrapers/hex.ts +2 -1
- package/src/web/scrapers/huggingface.ts +2 -1
- package/src/web/scrapers/jetbrains-marketplace.ts +2 -1
- package/src/web/scrapers/lemmy.ts +2 -1
- package/src/web/scrapers/lobsters.ts +2 -1
- package/src/web/scrapers/mastodon.ts +2 -1
- package/src/web/scrapers/maven.ts +2 -1
- package/src/web/scrapers/mdn.ts +2 -1
- package/src/web/scrapers/metacpan.ts +2 -1
- package/src/web/scrapers/musicbrainz.ts +3 -1
- package/src/web/scrapers/npm.ts +2 -1
- package/src/web/scrapers/nuget.ts +2 -1
- package/src/web/scrapers/nvd.ts +2 -1
- package/src/web/scrapers/ollama.ts +2 -1
- package/src/web/scrapers/open-vsx.ts +2 -1
- package/src/web/scrapers/opencorporates.ts +2 -1
- package/src/web/scrapers/openlibrary.ts +2 -1
- package/src/web/scrapers/orcid.ts +3 -1
- package/src/web/scrapers/osv.ts +2 -1
- package/src/web/scrapers/packagist.ts +2 -1
- package/src/web/scrapers/pub-dev.ts +2 -1
- package/src/web/scrapers/pubmed.ts +2 -1
- package/src/web/scrapers/pypi.ts +2 -1
- package/src/web/scrapers/rawg.ts +2 -8
- package/src/web/scrapers/reddit.ts +2 -1
- package/src/web/scrapers/repology.ts +2 -1
- package/src/web/scrapers/rfc.ts +2 -1
- package/src/web/scrapers/rubygems.ts +2 -1
- package/src/web/scrapers/searchcode.ts +2 -1
- package/src/web/scrapers/sec-edgar.ts +2 -1
- package/src/web/scrapers/semantic-scholar.ts +2 -1
- package/src/web/scrapers/snapcraft.ts +2 -1
- package/src/web/scrapers/sourcegraph.ts +2 -1
- package/src/web/scrapers/spdx.ts +2 -1
- package/src/web/scrapers/stackoverflow.ts +2 -1
- package/src/web/scrapers/terraform.ts +2 -1
- package/src/web/scrapers/types.ts +0 -11
- package/src/web/scrapers/vimeo.ts +2 -1
- package/src/web/scrapers/vscode-marketplace.ts +2 -1
- package/src/web/scrapers/w3c.ts +2 -1
- package/src/web/scrapers/wikidata.ts +2 -1
- package/src/web/search/index.ts +10 -14
- package/src/web/search/provider.ts +2 -2
- package/src/web/search/providers/codex.ts +1 -2
- package/src/web/search/providers/exa.ts +42 -10
- package/src/web/search/providers/gemini.ts +1 -1
- package/src/web/search/providers/perplexity.ts +20 -9
- package/src/web/search/providers/utils.ts +1 -1
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type AgentMessage,
|
|
24
24
|
type AgentState,
|
|
25
25
|
type AgentTool,
|
|
26
|
+
INTENT_FIELD,
|
|
26
27
|
type ThinkingLevel,
|
|
27
28
|
} from "@oh-my-pi/pi-agent-core";
|
|
28
29
|
import type {
|
|
@@ -38,8 +39,7 @@ import type {
|
|
|
38
39
|
UsageReport,
|
|
39
40
|
} from "@oh-my-pi/pi-ai";
|
|
40
41
|
import { isContextOverflow, modelsAreEqual, supportsXhigh } from "@oh-my-pi/pi-ai";
|
|
41
|
-
import { abortableSleep, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
42
|
-
import { getAgentDbPath } from "@oh-my-pi/pi-utils/dirs";
|
|
42
|
+
import { abortableSleep, getAgentDbPath, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
43
43
|
import type { AsyncJob, AsyncJobManager } from "../async";
|
|
44
44
|
import type { Rule } from "../capability/rule";
|
|
45
45
|
import { MODEL_ROLE_IDS, type ModelRegistry, type ModelRole } from "../config/model-registry";
|
|
@@ -84,8 +84,6 @@ import planModeActivePrompt from "../prompts/system/plan-mode-active.md" with {
|
|
|
84
84
|
import planModeReferencePrompt from "../prompts/system/plan-mode-reference.md" with { type: "text" };
|
|
85
85
|
import ttsrInterruptTemplate from "../prompts/system/ttsr-interrupt.md" with { type: "text" };
|
|
86
86
|
import type { SecretObfuscator } from "../secrets/obfuscator";
|
|
87
|
-
import { closeAllConnections } from "../ssh/connection-manager";
|
|
88
|
-
import { unmountAll } from "../ssh/sshfs-mount";
|
|
89
87
|
import { outputMeta } from "../tools/output-meta";
|
|
90
88
|
import { resolveToCwd } from "../tools/path-utils";
|
|
91
89
|
import { getLatestTodoPhasesFromEntries, type TodoItem, type TodoPhase } from "../tools/todo-write";
|
|
@@ -273,15 +271,6 @@ const noOpUIContext: ExtensionUIContext = {
|
|
|
273
271
|
setToolsExpanded: () => {},
|
|
274
272
|
};
|
|
275
273
|
|
|
276
|
-
async function cleanupSshResources(): Promise<void> {
|
|
277
|
-
const results = await Promise.allSettled([closeAllConnections(), unmountAll()]);
|
|
278
|
-
for (const result of results) {
|
|
279
|
-
if (result.status === "rejected") {
|
|
280
|
-
logger.warn("SSH cleanup failed", { error: String(result.reason) });
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
274
|
// ============================================================================
|
|
286
275
|
// AgentSession Class
|
|
287
276
|
// ============================================================================
|
|
@@ -1275,13 +1264,19 @@ export class AgentSession {
|
|
|
1275
1264
|
* Call this when completely done with the session.
|
|
1276
1265
|
*/
|
|
1277
1266
|
async dispose(): Promise<void> {
|
|
1267
|
+
try {
|
|
1268
|
+
if (this.#extensionRunner?.hasHandlers("session_shutdown")) {
|
|
1269
|
+
await this.#extensionRunner.emit({ type: "session_shutdown" });
|
|
1270
|
+
}
|
|
1271
|
+
} catch (error) {
|
|
1272
|
+
logger.warn("Failed to emit session_shutdown event", { error: String(error) });
|
|
1273
|
+
}
|
|
1278
1274
|
const drained = await this.#asyncJobManager?.dispose({ timeoutMs: 3_000 });
|
|
1279
1275
|
const deliveryState = this.#asyncJobManager?.getDeliveryState();
|
|
1280
1276
|
if (drained === false && deliveryState) {
|
|
1281
1277
|
logger.warn("Async job completion deliveries still pending during dispose", { ...deliveryState });
|
|
1282
1278
|
}
|
|
1283
1279
|
await this.sessionManager.flush();
|
|
1284
|
-
await cleanupSshResources();
|
|
1285
1280
|
for (const state of this.#providerSessionState.values()) {
|
|
1286
1281
|
state.close();
|
|
1287
1282
|
}
|
|
@@ -4615,7 +4610,7 @@ Be thorough - include exact file paths, function names, error messages, and tech
|
|
|
4615
4610
|
function formatArgsAsXml(args: Record<string, unknown>, indent = "\t"): string {
|
|
4616
4611
|
const parts: string[] = [];
|
|
4617
4612
|
for (const [key, value] of Object.entries(args)) {
|
|
4618
|
-
if (key ===
|
|
4613
|
+
if (key === INTENT_FIELD) continue;
|
|
4619
4614
|
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
4620
4615
|
parts.push(`${indent}<parameter name="${key}">${text}</parameter>`);
|
|
4621
4616
|
}
|
|
@@ -4861,15 +4856,4 @@ Be thorough - include exact file paths, function names, error messages, and tech
|
|
|
4861
4856
|
get extensionRunner(): ExtensionRunner | undefined {
|
|
4862
4857
|
return this.#extensionRunner;
|
|
4863
4858
|
}
|
|
4864
|
-
|
|
4865
|
-
/**
|
|
4866
|
-
* Emit a custom tool session event (backwards compatibility for older callers).
|
|
4867
|
-
*/
|
|
4868
|
-
async emitCustomToolSessionEvent(reason: "start" | "switch" | "branch" | "tree" | "shutdown"): Promise<void> {
|
|
4869
|
-
if (reason !== "shutdown") return;
|
|
4870
|
-
if (this.#extensionRunner?.hasHandlers("session_shutdown")) {
|
|
4871
|
-
await this.#extensionRunner.emit({ type: "session_shutdown" });
|
|
4872
|
-
}
|
|
4873
|
-
await cleanupSshResources();
|
|
4874
|
-
}
|
|
4875
4859
|
}
|
|
@@ -2,8 +2,7 @@ import { Database, type Statement } from "bun:sqlite";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { type AuthCredential, AuthCredentialStore, type StoredAuthCredential } from "@oh-my-pi/pi-ai";
|
|
5
|
-
import { isRecord, logger } from "@oh-my-pi/pi-utils";
|
|
6
|
-
import { getAgentDbPath } from "@oh-my-pi/pi-utils/dirs";
|
|
5
|
+
import { getAgentDbPath, isRecord, logger } from "@oh-my-pi/pi-utils";
|
|
7
6
|
import type { RawSettings as Settings } from "../config/settings";
|
|
8
7
|
|
|
9
8
|
/** Row shape for settings table queries */
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Database, type Statement } from "bun:sqlite";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import { logger } from "@oh-my-pi/pi-utils";
|
|
5
|
-
import { getAgentDir } from "@oh-my-pi/pi-utils/dirs";
|
|
4
|
+
import { getAgentDir, logger } from "@oh-my-pi/pi-utils";
|
|
6
5
|
|
|
7
6
|
export interface HistoryEntry {
|
|
8
7
|
id: number;
|
|
@@ -4,8 +4,16 @@ import * as path from "node:path";
|
|
|
4
4
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
5
5
|
import type { ImageContent, Message, TextContent, Usage } from "@oh-my-pi/pi-ai";
|
|
6
6
|
import { getTerminalId } from "@oh-my-pi/pi-tui";
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
getBlobsDir,
|
|
9
|
+
getAgentDir as getDefaultAgentDir,
|
|
10
|
+
getProjectDir,
|
|
11
|
+
isEnoent,
|
|
12
|
+
logger,
|
|
13
|
+
parseJsonlLenient,
|
|
14
|
+
Snowflake,
|
|
15
|
+
toError,
|
|
16
|
+
} from "@oh-my-pi/pi-utils";
|
|
9
17
|
import { ArtifactManager } from "./artifacts";
|
|
10
18
|
import { type BlobPutResult, BlobStore, externalizeImageData, isBlobRef, resolveImageData } from "./blob-store";
|
|
11
19
|
import {
|
|
@@ -259,7 +259,32 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
|
|
|
259
259
|
{
|
|
260
260
|
name: "login",
|
|
261
261
|
description: "Login with OAuth provider",
|
|
262
|
-
|
|
262
|
+
inlineHint: "[redirect URL]",
|
|
263
|
+
allowArgs: true,
|
|
264
|
+
handle: (command, runtime) => {
|
|
265
|
+
const manualInput = runtime.ctx.oauthManualInput;
|
|
266
|
+
const args = command.args.trim();
|
|
267
|
+
if (args.length > 0) {
|
|
268
|
+
const submitted = manualInput.submit(args);
|
|
269
|
+
if (submitted) {
|
|
270
|
+
runtime.ctx.showStatus("OAuth callback received; completing login…");
|
|
271
|
+
} else {
|
|
272
|
+
runtime.ctx.showWarning("No OAuth login is waiting for a manual callback.");
|
|
273
|
+
}
|
|
274
|
+
runtime.ctx.editor.setText("");
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (manualInput.hasPending()) {
|
|
279
|
+
const provider = manualInput.pendingProviderId;
|
|
280
|
+
const message = provider
|
|
281
|
+
? `OAuth login already in progress for ${provider}. Paste the redirect URL with /login <url>.`
|
|
282
|
+
: "OAuth login already in progress. Paste the redirect URL with /login <url>.";
|
|
283
|
+
runtime.ctx.showWarning(message);
|
|
284
|
+
runtime.ctx.editor.setText("");
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
263
288
|
void runtime.ctx.showOAuthSelector("login");
|
|
264
289
|
runtime.ctx.editor.setText("");
|
|
265
290
|
},
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
4
|
-
import { getRemoteHostDir, getSshControlDir } from "@oh-my-pi/pi-utils/dirs";
|
|
3
|
+
import { getRemoteHostDir, getSshControlDir, isEnoent, logger, postmortem } from "@oh-my-pi/pi-utils";
|
|
5
4
|
import { $ } from "bun";
|
|
6
5
|
import { buildSshTarget, sanitizeHostName } from "./utils";
|
|
7
6
|
|
|
@@ -69,6 +68,7 @@ async function validateKeyPermissions(keyPath?: string): Promise<void> {
|
|
|
69
68
|
|
|
70
69
|
function buildCommonArgs(host: SSHConnectionTarget): string[] {
|
|
71
70
|
const args = [
|
|
71
|
+
"-n",
|
|
72
72
|
"-o",
|
|
73
73
|
"ControlMaster=auto",
|
|
74
74
|
"-o",
|
|
@@ -362,6 +362,8 @@ export async function buildRemoteCommand(host: SSHConnectionTarget, command: str
|
|
|
362
362
|
return [...buildCommonArgs(host), buildSshTarget(host.username, host.host), command];
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
let registered = false;
|
|
366
|
+
|
|
365
367
|
export async function ensureConnection(host: SSHConnectionTarget): Promise<void> {
|
|
366
368
|
const key = host.name;
|
|
367
369
|
const pending = pendingConnections.get(key);
|
|
@@ -375,6 +377,13 @@ export async function ensureConnection(host: SSHConnectionTarget): Promise<void>
|
|
|
375
377
|
ensureControlDir();
|
|
376
378
|
await validateKeyPermissions(host.keyPath);
|
|
377
379
|
|
|
380
|
+
if (!registered) {
|
|
381
|
+
registered = true;
|
|
382
|
+
postmortem.register("ssh-cleanup", async () => {
|
|
383
|
+
await closeAllConnections();
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
378
387
|
const target = buildSshTarget(host.username, host.host);
|
|
379
388
|
const check = await runSshSync(["-O", "check", ...buildCommonArgs(host), target]);
|
|
380
389
|
if (check.exitCode === 0) {
|
package/src/ssh/sshfs-mount.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { getRemoteDir } from "@oh-my-pi/pi-utils
|
|
3
|
+
import { getRemoteDir, postmortem } from "@oh-my-pi/pi-utils";
|
|
4
4
|
import { $ } from "bun";
|
|
5
5
|
import { getControlDir, getControlPathTemplate, type SSHConnectionTarget } from "./connection-manager";
|
|
6
6
|
import { buildSshTarget, sanitizeHostName } from "./utils";
|
|
@@ -83,6 +83,8 @@ export async function isMounted(path: string): Promise<boolean> {
|
|
|
83
83
|
return result.exitCode === 0;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
let registered = false;
|
|
87
|
+
|
|
86
88
|
export async function mountRemote(host: SSHConnectionTarget, remotePath = "/"): Promise<string | undefined> {
|
|
87
89
|
if (!hasSshfs()) return undefined;
|
|
88
90
|
|
|
@@ -90,6 +92,10 @@ export async function mountRemote(host: SSHConnectionTarget, remotePath = "/"):
|
|
|
90
92
|
await Promise.all([ensureDir(REMOTE_DIR), ensureDir(CONTROL_DIR), ensureDir(mountPath)]);
|
|
91
93
|
|
|
92
94
|
if (await isMounted(mountPath)) {
|
|
95
|
+
if (!registered) {
|
|
96
|
+
registered = true;
|
|
97
|
+
postmortem.register("sshfs-cleanup", unmountAll);
|
|
98
|
+
}
|
|
93
99
|
mountedPaths.add(mountPath);
|
|
94
100
|
return mountPath;
|
|
95
101
|
}
|
package/src/system-prompt.ts
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as os from "node:os";
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
-
import { $env, hasFsCode, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
9
|
-
import { getGpuCachePath, getProjectDir } from "@oh-my-pi/pi-utils/dirs";
|
|
8
|
+
import { $env, getGpuCachePath, getProjectDir, hasFsCode, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
10
9
|
import { $ } from "bun";
|
|
11
10
|
import { contextFileCapability } from "./capability/context-file";
|
|
12
11
|
import { systemPromptCapability } from "./capability/system-prompt";
|
|
@@ -16,7 +15,6 @@ import { type ContextFile, loadCapability, type SystemPrompt as SystemPromptFile
|
|
|
16
15
|
import { loadSkills, type Skill } from "./extensibility/skills";
|
|
17
16
|
import customSystemPromptTemplate from "./prompts/system/custom-system-prompt.md" with { type: "text" };
|
|
18
17
|
import systemPromptTemplate from "./prompts/system/system-prompt.md" with { type: "text" };
|
|
19
|
-
import type { ToolName } from "./tools";
|
|
20
18
|
|
|
21
19
|
type PreloadedSkill = { name: string; content: string };
|
|
22
20
|
|
|
@@ -206,65 +204,6 @@ function getTerminalName(): string | undefined {
|
|
|
206
204
|
return term ?? undefined;
|
|
207
205
|
}
|
|
208
206
|
|
|
209
|
-
function normalizeDesktopValue(value: string): string | undefined {
|
|
210
|
-
const trimmed = value.trim();
|
|
211
|
-
if (!trimmed) return undefined;
|
|
212
|
-
const parts = trimmed
|
|
213
|
-
.split(":")
|
|
214
|
-
.map(part => part.trim())
|
|
215
|
-
.filter(Boolean);
|
|
216
|
-
return parts[0] ?? trimmed;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function getDesktopEnvironment(): string | undefined {
|
|
220
|
-
if (Bun.env.KDE_FULL_SESSION === "true") return "KDE";
|
|
221
|
-
const raw = firstNonEmpty(
|
|
222
|
-
Bun.env.XDG_CURRENT_DESKTOP,
|
|
223
|
-
Bun.env.DESKTOP_SESSION,
|
|
224
|
-
Bun.env.XDG_SESSION_DESKTOP,
|
|
225
|
-
Bun.env.GDMSESSION,
|
|
226
|
-
);
|
|
227
|
-
return raw ? normalizeDesktopValue(raw) : undefined;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function matchKnownWindowManager(value: string): string | null {
|
|
231
|
-
const normalized = value.toLowerCase();
|
|
232
|
-
const candidates = [
|
|
233
|
-
"sway",
|
|
234
|
-
"i3",
|
|
235
|
-
"i3wm",
|
|
236
|
-
"bspwm",
|
|
237
|
-
"openbox",
|
|
238
|
-
"awesome",
|
|
239
|
-
"herbstluftwm",
|
|
240
|
-
"fluxbox",
|
|
241
|
-
"icewm",
|
|
242
|
-
"dwm",
|
|
243
|
-
"hyprland",
|
|
244
|
-
"wayfire",
|
|
245
|
-
"river",
|
|
246
|
-
"labwc",
|
|
247
|
-
"qtile",
|
|
248
|
-
];
|
|
249
|
-
for (const candidate of candidates) {
|
|
250
|
-
if (normalized.includes(candidate)) return candidate;
|
|
251
|
-
}
|
|
252
|
-
return null;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function getWindowManager(): string | undefined {
|
|
256
|
-
const explicit = firstNonEmpty(Bun.env.WINDOWMANAGER);
|
|
257
|
-
if (explicit) return explicit;
|
|
258
|
-
|
|
259
|
-
const desktop = firstNonEmpty(Bun.env.XDG_CURRENT_DESKTOP, Bun.env.DESKTOP_SESSION);
|
|
260
|
-
if (desktop) {
|
|
261
|
-
const matched = matchKnownWindowManager(desktop);
|
|
262
|
-
if (matched) return matched;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return undefined;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
207
|
/** Cached system info structure */
|
|
269
208
|
interface GpuCache {
|
|
270
209
|
gpu: string;
|
|
@@ -308,13 +247,11 @@ async function getEnvironmentInfo(): Promise<Array<{ label: string; value: strin
|
|
|
308
247
|
{ label: "Distro", value: os.type() },
|
|
309
248
|
{ label: "Kernel", value: os.version() },
|
|
310
249
|
{ label: "Arch", value: os.arch() },
|
|
311
|
-
{ label: "CPU", value: `${cpus
|
|
250
|
+
{ label: "CPU", value: `${cpus[0]?.model}` },
|
|
312
251
|
{ label: "GPU", value: gpu },
|
|
313
252
|
{ label: "Terminal", value: getTerminalName() },
|
|
314
|
-
{ label: "DE", value: getDesktopEnvironment() },
|
|
315
|
-
{ label: "WM", value: getWindowManager() },
|
|
316
253
|
];
|
|
317
|
-
return entries.filter((e): e is { label: string; value: string } => e.value
|
|
254
|
+
return entries.filter((e): e is { label: string; value: string } => !!e.value);
|
|
318
255
|
}
|
|
319
256
|
|
|
320
257
|
/** Resolve input as file path or literal string */
|
|
@@ -421,6 +358,8 @@ export interface BuildSystemPromptOptions {
|
|
|
421
358
|
rules?: Array<{ name: string; description?: string; path: string; globs?: string[] }>;
|
|
422
359
|
/** Intent field name injected into every tool schema. If set, explains the field in the prompt. */
|
|
423
360
|
intentField?: string;
|
|
361
|
+
/** Encourage the agent to delegate via tasks unless changes are trivial. */
|
|
362
|
+
eagerTasks?: boolean;
|
|
424
363
|
}
|
|
425
364
|
|
|
426
365
|
/** Build the system prompt with tools, guidelines, and context */
|
|
@@ -435,13 +374,14 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
435
374
|
appendSystemPrompt,
|
|
436
375
|
repeatToolDescriptions = false,
|
|
437
376
|
skillsSettings,
|
|
438
|
-
toolNames,
|
|
377
|
+
toolNames: providedToolNames,
|
|
439
378
|
cwd,
|
|
440
379
|
contextFiles: providedContextFiles,
|
|
441
380
|
skills: providedSkills,
|
|
442
381
|
preloadedSkills: providedPreloadedSkills,
|
|
443
382
|
rules,
|
|
444
383
|
intentField,
|
|
384
|
+
eagerTasks = false,
|
|
445
385
|
} = options;
|
|
446
386
|
const resolvedCwd = cwd ?? getProjectDir();
|
|
447
387
|
const preloadedSkills = providedPreloadedSkills;
|
|
@@ -554,25 +494,24 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
554
494
|
timeZoneName: "short",
|
|
555
495
|
});
|
|
556
496
|
|
|
557
|
-
// Build tool
|
|
558
|
-
// Priority:
|
|
497
|
+
// Build tool metadata for system prompt rendering
|
|
498
|
+
// Priority: explicit list > tools map > defaults
|
|
559
499
|
// Default includes both bash and python; actual availability determined by settings in createTools
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
// Use defaults
|
|
570
|
-
toolNamesArray = defaultToolNames;
|
|
500
|
+
let toolNames = providedToolNames;
|
|
501
|
+
if (!toolNames) {
|
|
502
|
+
if (tools) {
|
|
503
|
+
// Tools map provided
|
|
504
|
+
toolNames = Array.from(tools.keys());
|
|
505
|
+
} else {
|
|
506
|
+
// Use defaults
|
|
507
|
+
toolNames = ["read", "bash", "python", "edit", "write"]; // TODO: Why?
|
|
508
|
+
}
|
|
571
509
|
}
|
|
572
510
|
|
|
573
511
|
// Build tool descriptions for system prompt rendering
|
|
574
|
-
const
|
|
512
|
+
const toolInfo = toolNames.map(name => ({
|
|
575
513
|
name,
|
|
514
|
+
label: tools?.get(name)?.label ?? "",
|
|
576
515
|
description: tools?.get(name)?.description ?? "",
|
|
577
516
|
}));
|
|
578
517
|
|
|
@@ -580,29 +519,15 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
580
519
|
const hasRead = tools?.has("read");
|
|
581
520
|
const filteredSkills = preloadedSkills === undefined && hasRead ? skills : [];
|
|
582
521
|
|
|
583
|
-
if (resolvedCustomPrompt) {
|
|
584
|
-
return renderPromptTemplate(customSystemPromptTemplate, {
|
|
585
|
-
systemPromptCustomization: systemPromptCustomization ?? "",
|
|
586
|
-
customPrompt: resolvedCustomPrompt,
|
|
587
|
-
appendPrompt: resolvedAppendPrompt ?? "",
|
|
588
|
-
contextFiles,
|
|
589
|
-
agentsMdSearch,
|
|
590
|
-
skills: filteredSkills,
|
|
591
|
-
preloadedSkills: preloadedSkillContents,
|
|
592
|
-
rules: rules ?? [],
|
|
593
|
-
date,
|
|
594
|
-
dateTime,
|
|
595
|
-
cwd: resolvedCwd,
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
|
|
599
522
|
const environment = await logger.timeAsync("getEnvironmentInfo", getEnvironmentInfo);
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
523
|
+
const data = {
|
|
524
|
+
systemPromptCustomization: systemPromptCustomization ?? "",
|
|
525
|
+
customPrompt: resolvedCustomPrompt,
|
|
526
|
+
appendPrompt: resolvedAppendPrompt ?? "",
|
|
527
|
+
tools: toolNames,
|
|
528
|
+
toolInfo,
|
|
603
529
|
repeatToolDescriptions,
|
|
604
530
|
environment,
|
|
605
|
-
systemPromptCustomization: systemPromptCustomization ?? "",
|
|
606
531
|
contextFiles,
|
|
607
532
|
agentsMdSearch,
|
|
608
533
|
skills: filteredSkills,
|
|
@@ -611,8 +536,9 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
611
536
|
date,
|
|
612
537
|
dateTime,
|
|
613
538
|
cwd: resolvedCwd,
|
|
614
|
-
appendSystemPrompt: resolvedAppendPrompt ?? "",
|
|
615
539
|
intentTracing: !!intentField,
|
|
616
540
|
intentField: intentField ?? "",
|
|
617
|
-
|
|
541
|
+
eagerTasks,
|
|
542
|
+
};
|
|
543
|
+
return renderPromptTemplate(resolvedCustomPrompt ? customSystemPromptTemplate : systemPromptTemplate, data);
|
|
618
544
|
}
|
package/src/task/agents.ts
CHANGED
|
@@ -108,7 +108,7 @@ export function parseAgent(
|
|
|
108
108
|
});
|
|
109
109
|
const fields = parseAgentFields(frontmatter);
|
|
110
110
|
if (!fields) {
|
|
111
|
-
throw new AgentParsingError(new Error(
|
|
111
|
+
throw new AgentParsingError(new Error(`Invalid agent field: ${filePath}\n${content}`), filePath);
|
|
112
112
|
}
|
|
113
113
|
return {
|
|
114
114
|
...fields,
|