@oh-my-pi/pi-coding-agent 15.5.3 → 15.5.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.
- package/CHANGELOG.md +29 -0
- package/dist/types/config/settings-schema.d.ts +27 -0
- package/dist/types/config.d.ts +31 -5
- package/dist/types/edit/file-snapshot-store.d.ts +18 -0
- package/dist/types/edit/hashline/diff.d.ts +30 -0
- package/dist/types/edit/hashline/execute.d.ts +29 -0
- package/dist/types/edit/hashline/filesystem.d.ts +57 -0
- package/dist/types/edit/hashline/index.d.ts +4 -0
- package/dist/types/edit/hashline/params.d.ts +12 -0
- package/dist/types/edit/index.d.ts +4 -3
- package/dist/types/edit/normalize.d.ts +4 -16
- package/dist/types/index.d.ts +0 -1
- package/dist/types/tools/index.d.ts +6 -5
- package/dist/types/tools/path-utils.d.ts +18 -0
- package/dist/types/utils/changelog.d.ts +8 -3
- package/package.json +8 -15
- package/src/config/settings-schema.ts +32 -0
- package/src/config.ts +42 -15
- package/src/edit/file-snapshot-store.ts +22 -0
- package/src/edit/hashline/diff.ts +88 -0
- package/src/edit/hashline/execute.ts +188 -0
- package/src/edit/hashline/filesystem.ts +129 -0
- package/src/edit/hashline/index.ts +4 -0
- package/src/edit/hashline/params.ts +11 -0
- package/src/edit/index.ts +7 -15
- package/src/edit/normalize.ts +11 -41
- package/src/edit/renderer.ts +1 -1
- package/src/edit/streaming.ts +8 -9
- package/src/index.ts +0 -1
- package/src/internal-urls/docs-index.generated.ts +1 -1
- package/src/sdk.ts +8 -1
- package/src/tools/ast-edit.ts +1 -1
- package/src/tools/ast-grep.ts +3 -3
- package/src/tools/index.ts +6 -5
- package/src/tools/path-utils.ts +81 -0
- package/src/tools/read.ts +14 -72
- package/src/tools/search.ts +136 -17
- package/src/tools/write.ts +3 -3
- package/src/utils/changelog.ts +11 -3
- package/src/utils/file-mentions.ts +1 -1
- package/dist/types/edit/file-read-cache.d.ts +0 -36
- package/dist/types/hashline/anchors.d.ts +0 -26
- package/dist/types/hashline/apply.d.ts +0 -14
- package/dist/types/hashline/constants.d.ts +0 -48
- package/dist/types/hashline/diff-preview.d.ts +0 -2
- package/dist/types/hashline/diff.d.ts +0 -16
- package/dist/types/hashline/execute.d.ts +0 -4
- package/dist/types/hashline/executor.d.ts +0 -56
- package/dist/types/hashline/hash.d.ts +0 -76
- package/dist/types/hashline/index.d.ts +0 -14
- package/dist/types/hashline/input.d.ts +0 -4
- package/dist/types/hashline/prefixes.d.ts +0 -7
- package/dist/types/hashline/recovery.d.ts +0 -21
- package/dist/types/hashline/stream.d.ts +0 -2
- package/dist/types/hashline/tokenizer.d.ts +0 -94
- package/dist/types/hashline/types.d.ts +0 -75
- package/src/edit/file-read-cache.ts +0 -138
- package/src/hashline/anchors.ts +0 -104
- package/src/hashline/apply.ts +0 -790
- package/src/hashline/bigrams.json +0 -649
- package/src/hashline/constants.ts +0 -60
- package/src/hashline/diff-preview.ts +0 -42
- package/src/hashline/diff.ts +0 -82
- package/src/hashline/execute.ts +0 -334
- package/src/hashline/executor.ts +0 -347
- package/src/hashline/grammar.lark +0 -22
- package/src/hashline/hash.ts +0 -131
- package/src/hashline/index.ts +0 -14
- package/src/hashline/input.ts +0 -137
- package/src/hashline/prefixes.ts +0 -111
- package/src/hashline/recovery.ts +0 -139
- package/src/hashline/stream.ts +0 -123
- package/src/hashline/tokenizer.ts +0 -473
- package/src/hashline/types.ts +0 -66
- package/src/prompts/tools/hashline.md +0 -83
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [15.5.4] - 2026-05-27
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- Removed the package root `hashline` export so imports from the top-level entrypoint can no longer access `hashline` helpers directly
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added `read.summarize.minTotalLines` setting (default 100) to set the minimum file length that triggers read summarization
|
|
14
|
+
- Added `<file>:<lines>` support to `search` `paths`, allowing file-scoped constraints such as `:N-M`, `:N+K`, and comma-separated ranges
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Changed multi-section hashline `edit` execution to defer LSP diagnostics flushing until the final section is written
|
|
19
|
+
- Changed read to return verbatim contents for files shorter than `read.summarize.minTotalLines` instead of summarizing them
|
|
20
|
+
- Changed `search` path line-range filtering to include only matches and context lines that fall inside the requested ranges
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Fixed multi-section hashline edits to reject duplicate canonical targets and preflight write guards before any section is committed
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Fixed `createAgentSession()` dropping the hidden `resolve` tool from the registry when no active tool sets `deferrable: true`, even though plan mode dispatches the plan-approval `resolve { action: "apply", ... }` call through a standing handler. Read-only plan-mode toolsets (e.g. `read`, `search`, `find`, `web_search`) silently activated plan mode without `resolve`, leaving the agent unable to submit the finalized plan and forcing the user to exit plan mode manually. `resolve` is now kept whenever `plan.enabled` is true, so the standing handler always has a callable tool ([#1428](https://github.com/can1357/oh-my-pi/issues/1428))
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Fixed `omp` startup and `/changelog` reading the host project's `CHANGELOG.md` as omp's — `getPackageDir()` no longer falls back to the user's `cwd` when no owning `package.json` is locatable, preventing spurious `lastChangelogVersion` writes ([#1423](https://github.com/can1357/oh-my-pi/issues/1423))
|
|
33
|
+
|
|
5
34
|
## [15.5.3] - 2026-05-27
|
|
6
35
|
### Breaking Changes
|
|
7
36
|
|
|
@@ -2015,6 +2015,33 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
2015
2015
|
readonly description: "Minimum multiline block comment length before read summaries collapse it";
|
|
2016
2016
|
};
|
|
2017
2017
|
};
|
|
2018
|
+
readonly "read.summarize.minTotalLines": {
|
|
2019
|
+
readonly type: "number";
|
|
2020
|
+
readonly default: 100;
|
|
2021
|
+
readonly ui: {
|
|
2022
|
+
readonly tab: "editing";
|
|
2023
|
+
readonly label: "Read Summary Minimum File Length";
|
|
2024
|
+
readonly description: "Files with fewer total lines are read verbatim instead of structurally summarized";
|
|
2025
|
+
};
|
|
2026
|
+
};
|
|
2027
|
+
readonly "read.summarize.unfoldUntil": {
|
|
2028
|
+
readonly type: "number";
|
|
2029
|
+
readonly default: 50;
|
|
2030
|
+
readonly ui: {
|
|
2031
|
+
readonly tab: "editing";
|
|
2032
|
+
readonly label: "Read Summary Unfold Target";
|
|
2033
|
+
readonly description: "BFS-unfold elidable spans until the summary is at least this many visible lines. 0 keeps only the outermost elisions.";
|
|
2034
|
+
};
|
|
2035
|
+
};
|
|
2036
|
+
readonly "read.summarize.unfoldLimit": {
|
|
2037
|
+
readonly type: "number";
|
|
2038
|
+
readonly default: 100;
|
|
2039
|
+
readonly ui: {
|
|
2040
|
+
readonly tab: "editing";
|
|
2041
|
+
readonly label: "Read Summary Unfold Ceiling";
|
|
2042
|
+
readonly description: "Hard ceiling on summary size while BFS-unfolding. An unfold that would exceed this is reverted and unfolding stops.";
|
|
2043
|
+
};
|
|
2044
|
+
};
|
|
2018
2045
|
readonly "read.toolResultPreview": {
|
|
2019
2046
|
readonly type: "boolean";
|
|
2020
2047
|
readonly default: false;
|
package/dist/types/config.d.ts
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
export * from "./config/config-file";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Walk up from `startDir` looking for a `package.json`. Returns the directory
|
|
4
|
+
* containing the marker, or `undefined` when the walk hits the filesystem root
|
|
5
|
+
* without finding one.
|
|
6
|
+
*
|
|
7
|
+
* Exported for unit-testing the resolution contract from arbitrary start
|
|
8
|
+
* directories (notably the `bun --compile` case where `import.meta.dir`
|
|
9
|
+
* resolves to `/$bunfs/root` and no owning package is locatable — issue
|
|
10
|
+
* #1423). Production callers should use {@link getPackageDir} instead.
|
|
11
|
+
*/
|
|
12
|
+
export declare function walkUpForPackageDir(startDir: string): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Get the base directory for resolving optional package assets (docs, examples, CHANGELOG.md).
|
|
15
|
+
*
|
|
16
|
+
* Honors the `PI_PACKAGE_DIR` override (useful for Nix/Guix store paths);
|
|
17
|
+
* otherwise walks up from `import.meta.dir` looking for a `package.json`.
|
|
18
|
+
* Returns `undefined` when no owning package is locatable — notably inside
|
|
19
|
+
* `bun --compile` binaries where `import.meta.dir` resolves to `/$bunfs/root`
|
|
20
|
+
* and the walk hits the filesystem root with nothing found.
|
|
21
|
+
*
|
|
22
|
+
* Callers MUST treat `undefined` as "no package assets available" and skip the
|
|
23
|
+
* lookup. NEVER fall back to the user's `cwd` here: that conflates the host
|
|
24
|
+
* project with omp's own assets and was the source of issue #1423 (the host
|
|
25
|
+
* project's `CHANGELOG.md` rendered as omp's startup changelog).
|
|
26
|
+
*/
|
|
27
|
+
export declare function getPackageDir(): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Path to omp's own `CHANGELOG.md`, or `undefined` when the package directory
|
|
30
|
+
* cannot be resolved (e.g. inside `bun --compile` binaries that don't bundle
|
|
31
|
+
* package assets). Callers MUST skip changelog parsing when this is undefined;
|
|
32
|
+
* see issue #1423.
|
|
5
33
|
*/
|
|
6
|
-
export declare function
|
|
7
|
-
/** Get path to CHANGELOG.md (optional, may not exist in binary) */
|
|
8
|
-
export declare function getChangelogPath(): string;
|
|
34
|
+
export declare function getChangelogPath(): string | undefined;
|
|
9
35
|
export interface ConfigDirEntry {
|
|
10
36
|
path: string;
|
|
11
37
|
source: string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-bound file snapshot store.
|
|
3
|
+
*
|
|
4
|
+
* Used by `read` and `search` to record exactly what the model saw, and by
|
|
5
|
+
* the hashline patcher to recover from stale section hashes (file changed
|
|
6
|
+
* externally between read and edit, or a prior in-session edit advanced
|
|
7
|
+
* the hash). The store is the {@link InMemorySnapshotStore} implementation
|
|
8
|
+
* from `@oh-my-pi/hashline`; the only coding-agent-specific concern here
|
|
9
|
+
* is wiring it onto the per-session {@link ToolSession} object.
|
|
10
|
+
*/
|
|
11
|
+
import { InMemorySnapshotStore } from "@oh-my-pi/hashline";
|
|
12
|
+
import type { ToolSession } from "../tools";
|
|
13
|
+
/**
|
|
14
|
+
* Look up (or lazily create) the file snapshot store attached to a session.
|
|
15
|
+
* Storage lives on `session.fileSnapshotStore` so it ages out exactly with
|
|
16
|
+
* the session itself.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getFileSnapshotStore(session: ToolSession): InMemorySnapshotStore;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only hashline diff preview helpers used by the streaming edit
|
|
3
|
+
* renderer. Reads the target file, parses + applies the section's edits in
|
|
4
|
+
* memory (no FS write, no LSP writethrough), then hands the before/after
|
|
5
|
+
* pair to {@link generateDiffString} so the renderer can show the diff
|
|
6
|
+
* while the tool call is still streaming.
|
|
7
|
+
*
|
|
8
|
+
* Validation is intentionally light: only the section file hash is checked
|
|
9
|
+
* (so the preview goes red when anchors are stale), no plan-mode guards
|
|
10
|
+
* and no auto-generated-file refusal — those belong on the write path.
|
|
11
|
+
*/
|
|
12
|
+
import { type PatchSection } from "@oh-my-pi/hashline";
|
|
13
|
+
export interface HashlineDiffOptions {
|
|
14
|
+
autoDropPureInsertDuplicates?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function computeHashlineSectionDiff(section: PatchSection, cwd: string, options?: HashlineDiffOptions): Promise<{
|
|
17
|
+
diff: string;
|
|
18
|
+
firstChangedLine: number | undefined;
|
|
19
|
+
} | {
|
|
20
|
+
error: string;
|
|
21
|
+
}>;
|
|
22
|
+
export declare function computeHashlineDiff(input: {
|
|
23
|
+
input: string;
|
|
24
|
+
path?: string;
|
|
25
|
+
}, cwd: string, options?: HashlineDiffOptions): Promise<{
|
|
26
|
+
diff: string;
|
|
27
|
+
firstChangedLine: number | undefined;
|
|
28
|
+
} | {
|
|
29
|
+
error: string;
|
|
30
|
+
}>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding-agent runner that drives the hashline {@link Patcher} on behalf of
|
|
3
|
+
* the `edit` tool. Converts a `{input, path?}` tool-call payload into a
|
|
4
|
+
* fully-applied patch, wraps the result in the agent's
|
|
5
|
+
* {@link AgentToolResult} shape, and attaches LSP diagnostics + `outputMeta`
|
|
6
|
+
* for the renderer.
|
|
7
|
+
*
|
|
8
|
+
* Multi-section patches are preflighted up front via {@link Patcher.prepare}
|
|
9
|
+
* so a partial batch never lands; the commit loop then narrows the LSP
|
|
10
|
+
* batch's `flush` flag to true only for the final write so diagnostics
|
|
11
|
+
* round-trip once.
|
|
12
|
+
*/
|
|
13
|
+
import { MismatchError as HashlineMismatchError } from "@oh-my-pi/hashline";
|
|
14
|
+
import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
15
|
+
import type { WritethroughCallback, WritethroughDeferredHandle } from "../../lsp";
|
|
16
|
+
import type { ToolSession } from "../../tools";
|
|
17
|
+
import type { EditToolDetails, LspBatchRequest } from "../renderer";
|
|
18
|
+
import { type HashlineParams, hashlineEditParamsSchema } from "./params";
|
|
19
|
+
export interface ExecuteHashlineSingleOptions {
|
|
20
|
+
session: ToolSession;
|
|
21
|
+
input: string;
|
|
22
|
+
path?: string;
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
batchRequest?: LspBatchRequest;
|
|
25
|
+
writethrough: WritethroughCallback;
|
|
26
|
+
beginDeferredDiagnosticsForPath: (path: string) => WritethroughDeferredHandle;
|
|
27
|
+
}
|
|
28
|
+
export declare function executeHashlineSingle(options: ExecuteHashlineSingleOptions): Promise<AgentToolResult<EditToolDetails, typeof hashlineEditParamsSchema>>;
|
|
29
|
+
export { HashlineMismatchError, type HashlineParams, hashlineEditParamsSchema };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding-agent specific {@link Filesystem} adapter for the hashline patcher.
|
|
3
|
+
*
|
|
4
|
+
* Wires hashline's storage abstraction to the agent runtime:
|
|
5
|
+
*
|
|
6
|
+
* - Section paths are resolved through the plan-mode redirect so a bare
|
|
7
|
+
* `PLAN.md` lands at the canonical session artifact location.
|
|
8
|
+
* - Reads go through `readEditFileText` (notebook-aware) and the
|
|
9
|
+
* auto-generated-file guard.
|
|
10
|
+
* - Writes go through `serializeEditFileText` (notebook-aware) and the
|
|
11
|
+
* LSP writethrough, with FS-scan cache invalidation on success. The
|
|
12
|
+
* resulting `FileDiagnosticsResult` is captured per-path so the
|
|
13
|
+
* orchestrator can attach it to the tool result.
|
|
14
|
+
*
|
|
15
|
+
* Construct one per `executeHashlineSingle` call: per-section state
|
|
16
|
+
* (batch request, diagnostics) lives on the instance and isn't safe to
|
|
17
|
+
* share across concurrent edit tools.
|
|
18
|
+
*/
|
|
19
|
+
import { Filesystem, type WriteResult } from "@oh-my-pi/hashline";
|
|
20
|
+
import type { FileDiagnosticsResult, WritethroughCallback, WritethroughDeferredHandle } from "../../lsp";
|
|
21
|
+
import type { ToolSession } from "../../tools";
|
|
22
|
+
import type { LspBatchRequest } from "../renderer";
|
|
23
|
+
export interface HashlineFilesystemOptions {
|
|
24
|
+
session: ToolSession;
|
|
25
|
+
writethrough: WritethroughCallback;
|
|
26
|
+
beginDeferredDiagnosticsForPath: (path: string) => WritethroughDeferredHandle;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
/**
|
|
29
|
+
* Outer LSP batch request inherited from the tool-call context. The
|
|
30
|
+
* orchestrator narrows this per-section (flush only on the final write)
|
|
31
|
+
* via {@link HashlineFilesystem.setBatchRequest}.
|
|
32
|
+
*/
|
|
33
|
+
batchRequest?: LspBatchRequest;
|
|
34
|
+
}
|
|
35
|
+
export declare class HashlineFilesystem extends Filesystem {
|
|
36
|
+
#private;
|
|
37
|
+
readonly session: ToolSession;
|
|
38
|
+
constructor(options: HashlineFilesystemOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Set the LSP batch request used for the next {@link writeText} call.
|
|
41
|
+
* Multi-section orchestrators flip the `flush` flag to true before the
|
|
42
|
+
* final section so LSP diagnostics flush in one round-trip.
|
|
43
|
+
*/
|
|
44
|
+
setBatchRequest(batchRequest: LspBatchRequest | undefined): void;
|
|
45
|
+
/**
|
|
46
|
+
* Look up (and clear) the diagnostics captured by the most-recent
|
|
47
|
+
* {@link writeText} call for `path`. Returns `undefined` if no write
|
|
48
|
+
* has happened or the writethrough returned no diagnostics.
|
|
49
|
+
*/
|
|
50
|
+
consumeDiagnostics(path: string): FileDiagnosticsResult | undefined;
|
|
51
|
+
resolveAbsolute(relativePath: string): string;
|
|
52
|
+
canonicalPath(relativePath: string): string;
|
|
53
|
+
readText(relativePath: string): Promise<string>;
|
|
54
|
+
preflightWrite(relativePath: string): Promise<void>;
|
|
55
|
+
writeText(relativePath: string, content: string): Promise<WriteResult>;
|
|
56
|
+
exists(relativePath: string): Promise<boolean>;
|
|
57
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schema for the `edit` tool's hashline mode payload. The schema is
|
|
3
|
+
* deliberately permissive (`.passthrough()`) so providers can attach extra
|
|
4
|
+
* keys without rejection; only `input` is required and `path` is an
|
|
5
|
+
* optional fallback used when the input lacks a `¶PATH#HASH` header.
|
|
6
|
+
*/
|
|
7
|
+
import * as z from "zod/v4";
|
|
8
|
+
export declare const hashlineEditParamsSchema: z.ZodObject<{
|
|
9
|
+
input: z.ZodString;
|
|
10
|
+
path: z.ZodOptional<z.ZodString>;
|
|
11
|
+
}, z.core.$loose>;
|
|
12
|
+
export type HashlineParams = z.infer<typeof hashlineEditParamsSchema>;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
|
-
import { type HashlineParams, hashlineEditParamsSchema } from "../hashline";
|
|
3
2
|
import type { ToolSession } from "../tools";
|
|
4
3
|
import { type EditMode } from "../utils/edit-mode";
|
|
4
|
+
import { type HashlineParams, hashlineEditParamsSchema } from "./hashline";
|
|
5
5
|
import { type ApplyPatchParams, applyPatchSchema } from "./modes/apply-patch";
|
|
6
6
|
import { type PatchParams, patchEditSchema } from "./modes/patch";
|
|
7
7
|
import { type ReplaceParams, replaceEditSchema } from "./modes/replace";
|
|
8
8
|
import { type EditToolDetails } from "./renderer";
|
|
9
|
+
export * from "@oh-my-pi/hashline";
|
|
9
10
|
export { DEFAULT_EDIT_MODE, type EditMode, normalizeEditMode } from "../utils/edit-mode";
|
|
10
11
|
export * from "./apply-patch";
|
|
11
12
|
export * from "./diff";
|
|
12
|
-
export * from "./file-
|
|
13
|
-
export * from "
|
|
13
|
+
export * from "./file-snapshot-store";
|
|
14
|
+
export * from "./hashline";
|
|
14
15
|
export * from "./modes/apply-patch";
|
|
15
16
|
export * from "./modes/patch";
|
|
16
17
|
export * from "./modes/replace";
|
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Text normalization utilities for the edit tool.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Whitespace, Unicode, and indentation helpers. Line-ending and BOM
|
|
5
|
+
* primitives live in `@oh-my-pi/hashline` and are re-exported here so
|
|
6
|
+
* existing consumers see one stable surface.
|
|
5
7
|
*/
|
|
6
|
-
export type LineEnding
|
|
7
|
-
/** Detect the predominant line ending in content */
|
|
8
|
-
export declare function detectLineEnding(content: string): LineEnding;
|
|
9
|
-
/** Normalize all line endings to LF */
|
|
10
|
-
export declare function normalizeToLF(text: string): string;
|
|
11
|
-
/** Restore line endings to the specified type */
|
|
12
|
-
export declare function restoreLineEndings(text: string, ending: LineEnding): string;
|
|
13
|
-
export interface BomResult {
|
|
14
|
-
/** The BOM character if present, empty string otherwise */
|
|
15
|
-
bom: string;
|
|
16
|
-
/** The text without the BOM */
|
|
17
|
-
text: string;
|
|
18
|
-
}
|
|
19
|
-
/** Strip UTF-8 BOM if present */
|
|
20
|
-
export declare function stripBom(content: string): BomResult;
|
|
8
|
+
export { type BomResult, detectLineEnding, type LineEnding, normalizeToLF, restoreLineEndings, stripBom, } from "@oh-my-pi/hashline";
|
|
21
9
|
/** Count leading whitespace characters in a line */
|
|
22
10
|
export declare function countLeadingWhitespace(line: string): number;
|
|
23
11
|
/** Get the leading whitespace string from a line */
|
package/dist/types/index.d.ts
CHANGED
|
@@ -14,7 +14,6 @@ export type * from "./extensibility/extensions";
|
|
|
14
14
|
export * from "./extensibility/extensions";
|
|
15
15
|
export * from "./extensibility/skills";
|
|
16
16
|
export { type FileSlashCommand, loadSlashCommands as discoverSlashCommands } from "./extensibility/slash-commands";
|
|
17
|
-
export * from "./hashline";
|
|
18
17
|
export type * from "./lsp";
|
|
19
18
|
export * from "./main";
|
|
20
19
|
export * from "./modes";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { InMemorySnapshotStore } from "@oh-my-pi/hashline";
|
|
1
2
|
import type { AgentTelemetryConfig, AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
3
|
import type { ToolChoice } from "@oh-my-pi/pi-ai";
|
|
3
4
|
import type { PromptTemplate } from "../config/prompt-templates";
|
|
@@ -188,11 +189,11 @@ export interface ToolSession {
|
|
|
188
189
|
getCheckpointState?: () => CheckpointState | undefined;
|
|
189
190
|
/** Set or clear active checkpoint state. */
|
|
190
191
|
setCheckpointState?: (state: CheckpointState | null) => void;
|
|
191
|
-
/** Per-session
|
|
192
|
-
* `read`/`search`. Used by hashline anchor-stale recovery to
|
|
193
|
-
* the version the model authored anchors against when the
|
|
194
|
-
* out-of-band. Lazily initialized by `
|
|
195
|
-
|
|
192
|
+
/** Per-session snapshot store of file contents as last shown to the model
|
|
193
|
+
* by `read`/`search`. Used by hashline anchor-stale recovery to
|
|
194
|
+
* reconstruct the version the model authored anchors against when the
|
|
195
|
+
* file changed out-of-band. Lazily initialized by `getFileSnapshotStore`. */
|
|
196
|
+
fileSnapshotStore?: InMemorySnapshotStore;
|
|
196
197
|
/** Per-session log of unresolved git merge conflict regions surfaced by
|
|
197
198
|
* `read`. Each entry gets a stable id N referenced by `write conflict://N`
|
|
198
199
|
* to splice the recorded region with replacement content. Lazily initialized
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
export declare function expandTilde(filePath: string, home?: string): string;
|
|
2
2
|
export declare function expandPath(filePath: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Inclusive line range describing one selector segment (e.g. `50-100`,
|
|
5
|
+
* `301-`, or `50+10`). `endLine` is `undefined` for open-ended ranges.
|
|
6
|
+
*/
|
|
7
|
+
export interface LineRange {
|
|
8
|
+
startLine: number;
|
|
9
|
+
endLine: number | undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Parse a single `N`, `N-M`, `N-`, or `N+K` chunk. Throws via {@link ToolError} on invalid bounds. */
|
|
12
|
+
export declare function parseLineRangeChunk(sel: string): LineRange | null;
|
|
13
|
+
/**
|
|
14
|
+
* Parse a comma-separated list of line ranges (e.g. `5-16,960-973`). Returns
|
|
15
|
+
* the ranges in ascending order with overlapping/adjacent ranges merged so
|
|
16
|
+
* downstream consumers can stream the file in a single forward pass per range.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseLineRanges(sel: string): [LineRange, ...LineRange[]] | null;
|
|
19
|
+
/** Return `true` when `lineNumber` (1-indexed) falls in any of the supplied ranges. */
|
|
20
|
+
export declare function isLineInRanges(lineNumber: number, ranges: readonly LineRange[]): boolean;
|
|
3
21
|
export declare function splitPathAndSel(rawPath: string): {
|
|
4
22
|
path: string;
|
|
5
23
|
sel?: string;
|
|
@@ -5,10 +5,15 @@ export interface ChangelogEntry {
|
|
|
5
5
|
content: string;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Parse changelog entries from
|
|
9
|
-
*
|
|
8
|
+
* Parse changelog entries from the file at `changelogPath`. Scans for `## [x.y.z]`
|
|
9
|
+
* headings and collects each block until the next heading or EOF.
|
|
10
|
+
*
|
|
11
|
+
* Returns `[]` when `changelogPath` is `undefined` (package directory not
|
|
12
|
+
* resolvable — see `getChangelogPath`) or the file is missing. Callers MUST NOT
|
|
13
|
+
* synthesize a fallback path from the host project's cwd; doing so caused issue
|
|
14
|
+
* #1423 (the host project's `CHANGELOG.md` was rendered as omp's).
|
|
10
15
|
*/
|
|
11
|
-
export declare function parseChangelog(changelogPath: string): Promise<ChangelogEntry[]>;
|
|
16
|
+
export declare function parseChangelog(changelogPath: string | undefined): Promise<ChangelogEntry[]>;
|
|
12
17
|
/**
|
|
13
18
|
* Compare versions. Returns: -1 if v1 < v2, 0 if v1 === v2, 1 if v1 > v2
|
|
14
19
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "15.5.
|
|
4
|
+
"version": "15.5.4",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -47,12 +47,13 @@
|
|
|
47
47
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
48
48
|
"@babel/parser": "^7.29.3",
|
|
49
49
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/
|
|
51
|
-
"@oh-my-pi/
|
|
52
|
-
"@oh-my-pi/pi-
|
|
53
|
-
"@oh-my-pi/pi-
|
|
54
|
-
"@oh-my-pi/pi-
|
|
55
|
-
"@oh-my-pi/pi-
|
|
50
|
+
"@oh-my-pi/hashline": "15.5.4",
|
|
51
|
+
"@oh-my-pi/omp-stats": "15.5.4",
|
|
52
|
+
"@oh-my-pi/pi-agent-core": "15.5.4",
|
|
53
|
+
"@oh-my-pi/pi-ai": "15.5.4",
|
|
54
|
+
"@oh-my-pi/pi-natives": "15.5.4",
|
|
55
|
+
"@oh-my-pi/pi-tui": "15.5.4",
|
|
56
|
+
"@oh-my-pi/pi-utils": "15.5.4",
|
|
56
57
|
"@puppeteer/browsers": "^2.13.0",
|
|
57
58
|
"@types/turndown": "5.0.6",
|
|
58
59
|
"@xterm/headless": "^6.0.0",
|
|
@@ -227,14 +228,6 @@
|
|
|
227
228
|
"types": "./dist/types/edit/modes/*.d.ts",
|
|
228
229
|
"import": "./src/edit/modes/*.ts"
|
|
229
230
|
},
|
|
230
|
-
"./hashline": {
|
|
231
|
-
"types": "./dist/types/hashline/index.d.ts",
|
|
232
|
-
"import": "./src/hashline/index.ts"
|
|
233
|
-
},
|
|
234
|
-
"./hashline/*": {
|
|
235
|
-
"types": "./dist/types/hashline/*.d.ts",
|
|
236
|
-
"import": "./src/hashline/*.ts"
|
|
237
|
-
},
|
|
238
231
|
"./exa": {
|
|
239
232
|
"types": "./dist/types/exa/index.d.ts",
|
|
240
233
|
"import": "./src/exa/index.ts"
|
|
@@ -1666,6 +1666,38 @@ export const SETTINGS_SCHEMA = {
|
|
|
1666
1666
|
},
|
|
1667
1667
|
},
|
|
1668
1668
|
|
|
1669
|
+
"read.summarize.minTotalLines": {
|
|
1670
|
+
type: "number",
|
|
1671
|
+
default: 100,
|
|
1672
|
+
ui: {
|
|
1673
|
+
tab: "editing",
|
|
1674
|
+
label: "Read Summary Minimum File Length",
|
|
1675
|
+
description: "Files with fewer total lines are read verbatim instead of structurally summarized",
|
|
1676
|
+
},
|
|
1677
|
+
},
|
|
1678
|
+
|
|
1679
|
+
"read.summarize.unfoldUntil": {
|
|
1680
|
+
type: "number",
|
|
1681
|
+
default: 50,
|
|
1682
|
+
ui: {
|
|
1683
|
+
tab: "editing",
|
|
1684
|
+
label: "Read Summary Unfold Target",
|
|
1685
|
+
description:
|
|
1686
|
+
"BFS-unfold elidable spans until the summary is at least this many visible lines. 0 keeps only the outermost elisions.",
|
|
1687
|
+
},
|
|
1688
|
+
},
|
|
1689
|
+
|
|
1690
|
+
"read.summarize.unfoldLimit": {
|
|
1691
|
+
type: "number",
|
|
1692
|
+
default: 100,
|
|
1693
|
+
ui: {
|
|
1694
|
+
tab: "editing",
|
|
1695
|
+
label: "Read Summary Unfold Ceiling",
|
|
1696
|
+
description:
|
|
1697
|
+
"Hard ceiling on summary size while BFS-unfolding. An unfold that would exceed this is reverted and unfolding stops.",
|
|
1698
|
+
},
|
|
1699
|
+
},
|
|
1700
|
+
|
|
1669
1701
|
"read.toolResultPreview": {
|
|
1670
1702
|
type: "boolean",
|
|
1671
1703
|
default: false,
|
package/src/config.ts
CHANGED
|
@@ -18,30 +18,57 @@ const priorityList = [
|
|
|
18
18
|
// =============================================================================
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
21
|
+
* Walk up from `startDir` looking for a `package.json`. Returns the directory
|
|
22
|
+
* containing the marker, or `undefined` when the walk hits the filesystem root
|
|
23
|
+
* without finding one.
|
|
24
|
+
*
|
|
25
|
+
* Exported for unit-testing the resolution contract from arbitrary start
|
|
26
|
+
* directories (notably the `bun --compile` case where `import.meta.dir`
|
|
27
|
+
* resolves to `/$bunfs/root` and no owning package is locatable — issue
|
|
28
|
+
* #1423). Production callers should use {@link getPackageDir} instead.
|
|
23
29
|
*/
|
|
24
|
-
export function
|
|
25
|
-
|
|
26
|
-
const envDir = process.env.PI_PACKAGE_DIR;
|
|
27
|
-
if (envDir) {
|
|
28
|
-
return expandTilde(envDir);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
let dir = import.meta.dir;
|
|
30
|
+
export function walkUpForPackageDir(startDir: string): string | undefined {
|
|
31
|
+
let dir = startDir;
|
|
32
32
|
while (dir !== path.dirname(dir)) {
|
|
33
33
|
if (fs.existsSync(path.join(dir, "package.json"))) {
|
|
34
34
|
return dir;
|
|
35
35
|
}
|
|
36
36
|
dir = path.dirname(dir);
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
return getProjectDir();
|
|
38
|
+
return undefined;
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Get the base directory for resolving optional package assets (docs, examples, CHANGELOG.md).
|
|
43
|
+
*
|
|
44
|
+
* Honors the `PI_PACKAGE_DIR` override (useful for Nix/Guix store paths);
|
|
45
|
+
* otherwise walks up from `import.meta.dir` looking for a `package.json`.
|
|
46
|
+
* Returns `undefined` when no owning package is locatable — notably inside
|
|
47
|
+
* `bun --compile` binaries where `import.meta.dir` resolves to `/$bunfs/root`
|
|
48
|
+
* and the walk hits the filesystem root with nothing found.
|
|
49
|
+
*
|
|
50
|
+
* Callers MUST treat `undefined` as "no package assets available" and skip the
|
|
51
|
+
* lookup. NEVER fall back to the user's `cwd` here: that conflates the host
|
|
52
|
+
* project with omp's own assets and was the source of issue #1423 (the host
|
|
53
|
+
* project's `CHANGELOG.md` rendered as omp's startup changelog).
|
|
54
|
+
*/
|
|
55
|
+
export function getPackageDir(): string | undefined {
|
|
56
|
+
const envDir = process.env.PI_PACKAGE_DIR;
|
|
57
|
+
if (envDir) {
|
|
58
|
+
return expandTilde(envDir);
|
|
59
|
+
}
|
|
60
|
+
return walkUpForPackageDir(import.meta.dir);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Path to omp's own `CHANGELOG.md`, or `undefined` when the package directory
|
|
65
|
+
* cannot be resolved (e.g. inside `bun --compile` binaries that don't bundle
|
|
66
|
+
* package assets). Callers MUST skip changelog parsing when this is undefined;
|
|
67
|
+
* see issue #1423.
|
|
68
|
+
*/
|
|
69
|
+
export function getChangelogPath(): string | undefined {
|
|
70
|
+
const packageDir = getPackageDir();
|
|
71
|
+
return packageDir ? path.resolve(packageDir, "CHANGELOG.md") : undefined;
|
|
45
72
|
}
|
|
46
73
|
|
|
47
74
|
// =============================================================================
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-bound file snapshot store.
|
|
3
|
+
*
|
|
4
|
+
* Used by `read` and `search` to record exactly what the model saw, and by
|
|
5
|
+
* the hashline patcher to recover from stale section hashes (file changed
|
|
6
|
+
* externally between read and edit, or a prior in-session edit advanced
|
|
7
|
+
* the hash). The store is the {@link InMemorySnapshotStore} implementation
|
|
8
|
+
* from `@oh-my-pi/hashline`; the only coding-agent-specific concern here
|
|
9
|
+
* is wiring it onto the per-session {@link ToolSession} object.
|
|
10
|
+
*/
|
|
11
|
+
import { InMemorySnapshotStore } from "@oh-my-pi/hashline";
|
|
12
|
+
import type { ToolSession } from "../tools";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Look up (or lazily create) the file snapshot store attached to a session.
|
|
16
|
+
* Storage lives on `session.fileSnapshotStore` so it ages out exactly with
|
|
17
|
+
* the session itself.
|
|
18
|
+
*/
|
|
19
|
+
export function getFileSnapshotStore(session: ToolSession): InMemorySnapshotStore {
|
|
20
|
+
if (!session.fileSnapshotStore) session.fileSnapshotStore = new InMemorySnapshotStore();
|
|
21
|
+
return session.fileSnapshotStore;
|
|
22
|
+
}
|