mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 08:35:57 +00:00
feat: add hashline editing and TypeScript LSP
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const BUNDLE_CONFIG_PATH = fileURLToPath(new URL("../config/pi-hashline-edit.json", import.meta.url));
|
||||
|
||||
export function deployBundleHashlineConfig(agentDir: string): void {
|
||||
const targetPath = join(agentDir, "hashline.json");
|
||||
const bundledConfig = readFileSync(BUNDLE_CONFIG_PATH, "utf8");
|
||||
|
||||
try {
|
||||
if (readFileSync(targetPath, "utf8") === bundledConfig) {
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Missing or unreadable target: replace it with the bundle-owned defaults.
|
||||
}
|
||||
|
||||
mkdirSync(dirname(targetPath), { recursive: true });
|
||||
const temporaryPath = `${targetPath}.my-pi.tmp`;
|
||||
writeFileSync(temporaryPath, bundledConfig, "utf8");
|
||||
renameSync(temporaryPath, targetPath);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { getAgentDir, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
import { deployBundleHashlineConfig } from "./hashline-config.ts";
|
||||
|
||||
/** Deploy bundle defaults before pi-hashline-edit reads its module-level config. */
|
||||
export default async function bundledHashlineExtension(pi: ExtensionAPI): Promise<void> {
|
||||
deployBundleHashlineConfig(getAgentDir());
|
||||
const { default: hashlineExtension } = await import("../node_modules/pi-hashline-edit/index.ts");
|
||||
hashlineExtension(pi);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const BUNDLE_CONFIG_PATH = fileURLToPath(new URL("../config/lsp.json", import.meta.url));
|
||||
const TYPESCRIPT_SERVER_ID = "typescript-language-server";
|
||||
|
||||
interface LspConfigFile {
|
||||
version?: number;
|
||||
servers?: Array<{
|
||||
id?: string;
|
||||
bin?: string;
|
||||
args?: string[];
|
||||
[key: string]: unknown;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface TypeScriptLspRuntime {
|
||||
nodeBinary: string;
|
||||
serverCliPath: string;
|
||||
}
|
||||
|
||||
export function materializeBundleLspConfig(source: string, runtime: TypeScriptLspRuntime): string {
|
||||
const config = JSON.parse(source) as LspConfigFile;
|
||||
const server = config.servers?.find((entry) => entry.id === TYPESCRIPT_SERVER_ID);
|
||||
if (server === undefined) {
|
||||
throw new Error(`Missing ${TYPESCRIPT_SERVER_ID} entry in bundled LSP config`);
|
||||
}
|
||||
|
||||
server.bin = runtime.nodeBinary;
|
||||
server.args = [runtime.serverCliPath, "--stdio"];
|
||||
return `${JSON.stringify(config, null, 2)}\n`;
|
||||
}
|
||||
|
||||
export function deployBundleLspConfig(agentDir: string, runtime: TypeScriptLspRuntime): void {
|
||||
const targetPath = join(agentDir, "lsp.json");
|
||||
const bundledConfig = materializeBundleLspConfig(readFileSync(BUNDLE_CONFIG_PATH, "utf8"), runtime);
|
||||
|
||||
try {
|
||||
if (readFileSync(targetPath, "utf8") === bundledConfig) return;
|
||||
} catch {
|
||||
// Missing or unreadable target: replace it with the bundle-owned baseline.
|
||||
}
|
||||
|
||||
mkdirSync(dirname(targetPath), { recursive: true });
|
||||
const temporaryPath = `${targetPath}.my-pi.tmp`;
|
||||
writeFileSync(temporaryPath, bundledConfig, "utf8");
|
||||
renameSync(temporaryPath, targetPath);
|
||||
}
|
||||
+8
-19
@@ -1,28 +1,17 @@
|
||||
import lspExtension from "../node_modules/pi-lsp/extensions/pi-lsp/index.ts";
|
||||
import { getAgentDir, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
import { readFileSync, renameSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { deployBundleLspConfig } from "./lsp-config.ts";
|
||||
|
||||
const BUNDLE_CONFIG_PATH = fileURLToPath(new URL("../config/lsp.json", import.meta.url));
|
||||
|
||||
function deployBundleLspConfig(): void {
|
||||
const targetPath = join(getAgentDir(), "lsp.json");
|
||||
const bundledConfig = readFileSync(BUNDLE_CONFIG_PATH, "utf8");
|
||||
|
||||
try {
|
||||
if (readFileSync(targetPath, "utf8") === bundledConfig) return;
|
||||
} catch {
|
||||
// Missing or unreadable target: replace it with the bundle-owned baseline.
|
||||
}
|
||||
|
||||
const temporaryPath = `${targetPath}.my-pi.tmp`;
|
||||
writeFileSync(temporaryPath, bundledConfig, "utf8");
|
||||
renameSync(temporaryPath, targetPath);
|
||||
}
|
||||
const TYPESCRIPT_LANGUAGE_SERVER_CLI = fileURLToPath(
|
||||
new URL("../node_modules/typescript-language-server/lib/cli.mjs", import.meta.url),
|
||||
);
|
||||
|
||||
/** Deploy the bundle-owned LSP config before registering pi-lsp. */
|
||||
export default function bundledLspExtension(pi: ExtensionAPI): void {
|
||||
deployBundleLspConfig();
|
||||
deployBundleLspConfig(getAgentDir(), {
|
||||
nodeBinary: process.execPath,
|
||||
serverCliPath: TYPESCRIPT_LANGUAGE_SERVER_CLI,
|
||||
});
|
||||
lspExtension(pi);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,16 @@ export function buildToolRoutingSection(selectedTools: SelectedTools): string {
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
hasTool(selectedTools, "lsp_definition") ||
|
||||
hasTool(selectedTools, "lsp_references") ||
|
||||
hasTool(selectedTools, "lsp_diagnostics")
|
||||
) {
|
||||
rules.push(
|
||||
"- Use LSP for symbol definitions, references, hover/type information, and post-edit diagnostics when the language server supports the file.",
|
||||
);
|
||||
}
|
||||
|
||||
if (hasTool(selectedTools, "find") || hasTool(selectedTools, "grep") || hasTool(selectedTools, "multi_grep")) {
|
||||
rules.push(
|
||||
"- For literal search, narrow in stages instead of requesting a repository-wide dump:",
|
||||
@@ -32,7 +42,7 @@ export function buildToolRoutingSection(selectedTools: SelectedTools): string {
|
||||
|
||||
if (hasTool(selectedTools, "ctx_execute") || hasTool(selectedTools, "ctx_execute_file")) {
|
||||
rules.push(
|
||||
"- Use Context Mode for logs, test/build output, generated data, large-file analysis, and any command whose output may be large or unpredictable. Print only the derived answer needed for the task.",
|
||||
"- Use Context Mode for logs, test/build output, generated data, large-file exploration/analysis/summarization, and any command whose output may be large or unpredictable. Prefer ctx_execute_file over read when deriving an answer from a large file inside the workspace, and print only the derived answer needed for the task.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,7 +54,13 @@ export function buildToolRoutingSection(selectedTools: SelectedTools): string {
|
||||
|
||||
if (hasTool(selectedTools, "read")) {
|
||||
rules.push(
|
||||
"- Use read directly when exact text is needed for editing or when a file is small. Do not read a complete large file merely to copy, compare, hash, count, or summarize it.",
|
||||
"- Use read only when exact source is needed or the file is small. Before editing, request the smallest useful offset/limit range; do not read a complete large file merely to copy, compare, hash, count, explore, or summarize it.",
|
||||
);
|
||||
}
|
||||
|
||||
if (hasTool(selectedTools, "read") && hasTool(selectedTools, "edit")) {
|
||||
rules.push(
|
||||
"- For existing-file changes, obtain fresh LINE#HASH anchors with a small read, then use anchored edit operations. Reuse fresh anchors returned by successful edits for chained changes; re-read only when anchors are stale or the next target region was not shown.",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user