@frenchtoastman/oh-my-groundcontrol 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/agents/maat.d.ts +2 -0
  2. package/dist/agents/ptah/behavioral-summary.d.ts +7 -0
  3. package/dist/agents/ptah/gemini.d.ts +11 -0
  4. package/dist/agents/ptah/gpt.d.ts +10 -0
  5. package/dist/agents/ptah/high-accuracy-mode.d.ts +6 -0
  6. package/dist/agents/ptah/identity-constraints.d.ts +7 -0
  7. package/dist/agents/ptah/index.d.ts +3 -0
  8. package/dist/agents/ptah/interview-mode.d.ts +8 -0
  9. package/dist/agents/ptah/plan-generation.d.ts +7 -0
  10. package/dist/agents/ptah/plan-template.d.ts +7 -0
  11. package/dist/agents/ptah/system-prompt.d.ts +20 -0
  12. package/dist/agents/sia.d.ts +2 -0
  13. package/dist/cli/index.js +21 -5
  14. package/dist/config/constants.d.ts +2 -2
  15. package/dist/config/schema.d.ts +51 -2
  16. package/dist/features/tool-metadata-store/index.d.ts +1 -0
  17. package/dist/features/tool-metadata-store/store.d.ts +8 -0
  18. package/dist/hooks/edit-error-recovery/index.d.ts +18 -0
  19. package/dist/hooks/hashline-read-enhancer/index.d.ts +22 -0
  20. package/dist/hooks/index.d.ts +2 -0
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +5066 -926
  23. package/dist/tools/hashline-edit/autocorrect-replacement-lines.d.ts +8 -0
  24. package/dist/tools/hashline-edit/constants.d.ts +11 -0
  25. package/dist/tools/hashline-edit/diff-utils.d.ts +16 -0
  26. package/dist/tools/hashline-edit/edit-deduplication.d.ts +9 -0
  27. package/dist/tools/hashline-edit/edit-operation-primitives.d.ts +16 -0
  28. package/dist/tools/hashline-edit/edit-operations.d.ts +16 -0
  29. package/dist/tools/hashline-edit/edit-ordering.d.ts +16 -0
  30. package/dist/tools/hashline-edit/edit-text-normalization.d.ts +36 -0
  31. package/dist/tools/hashline-edit/file-text-canonicalization.d.ts +14 -0
  32. package/dist/tools/hashline-edit/hash-computation.d.ts +28 -0
  33. package/dist/tools/hashline-edit/hashline-chunk-formatter.d.ts +14 -0
  34. package/dist/tools/hashline-edit/hashline-edit-executor.d.ts +17 -0
  35. package/dist/tools/hashline-edit/index.d.ts +6 -0
  36. package/dist/tools/hashline-edit/normalize-edits.d.ts +12 -0
  37. package/dist/tools/hashline-edit/tool-description.d.ts +1 -0
  38. package/dist/tools/hashline-edit/tools.d.ts +5 -0
  39. package/dist/tools/hashline-edit/types.d.ts +17 -0
  40. package/dist/tools/hashline-edit/validation.d.ts +35 -0
  41. package/dist/tools/index.d.ts +1 -0
  42. package/package.json +3 -1
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Autocorrection pipeline for LLM replacement text.
3
+ * Fixes common LLM mistakes: merged lines, wrapped lines, lost indentation.
4
+ */
5
+ /**
6
+ * Apply the full autocorrection pipeline.
7
+ */
8
+ export declare function autocorrectReplacementLines(originalLines: string[], replacementLines: string[]): string[];
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Nibble encoding alphabet – 16 uppercase letters, no digits, no vowels.
3
+ * Each byte maps to exactly two characters (high nibble + low nibble).
4
+ */
5
+ export declare const NIBBLE_STR = "ZPMQVRWSNKTXJBYH";
6
+ /** Pre-computed 256-entry lookup: byte value → 2-char hash fragment. */
7
+ export declare const HASHLINE_DICT: string[];
8
+ /** Matches a standalone LINE#HASH reference (e.g. "42#VK"). */
9
+ export declare const HASHLINE_REF_PATTERN: RegExp;
10
+ /** Matches a hashline-prefixed output line (e.g. "42#VK|content"). */
11
+ export declare const HASHLINE_OUTPUT_PATTERN: RegExp;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Add LINE#HASH| prefixes to content for display.
3
+ */
4
+ export declare function toHashlineContent(content: string): string;
5
+ /**
6
+ * Generate a unified diff between old and new content.
7
+ */
8
+ export declare function generateUnifiedDiff(oldContent: string, newContent: string, filePath: string): string;
9
+ /**
10
+ * Count line additions and deletions between old and new content.
11
+ * Uses frequency-based counting (not positional diff).
12
+ */
13
+ export declare function countLineDiffs(oldContent: string, newContent: string): {
14
+ additions: number;
15
+ deletions: number;
16
+ };
@@ -0,0 +1,9 @@
1
+ import type { HashlineEdit } from './types';
2
+ /**
3
+ * Deduplicate edits by building a canonical string key per edit.
4
+ * Returns the unique edits and a list of deduplicated ones.
5
+ */
6
+ export declare function dedupeEdits(edits: HashlineEdit[]): {
7
+ edits: HashlineEdit[];
8
+ deduplicatedEdits: HashlineEdit[];
9
+ };
@@ -0,0 +1,16 @@
1
+ interface EditOptions {
2
+ skipValidation?: boolean;
3
+ }
4
+ /** Replace a single line at anchor position. */
5
+ export declare function applySetLine(lines: string[], anchor: string, newText: string | string[], opts?: EditOptions): string[];
6
+ /** Replace a range of lines between start and end anchors (inclusive). */
7
+ export declare function applyReplaceLines(lines: string[], startAnchor: string, endAnchor: string, newText: string | string[], opts?: EditOptions): string[];
8
+ /** Insert lines after the anchor line. */
9
+ export declare function applyInsertAfter(lines: string[], anchor: string, text: string | string[], opts?: EditOptions): string[];
10
+ /** Insert lines before the anchor line. */
11
+ export declare function applyInsertBefore(lines: string[], anchor: string, text: string | string[], opts?: EditOptions): string[];
12
+ /** Append lines at the end of the file. */
13
+ export declare function applyAppend(lines: string[], text: string | string[]): string[];
14
+ /** Prepend lines at the beginning of the file. */
15
+ export declare function applyPrepend(lines: string[], text: string | string[]): string[];
16
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { HashlineEdit } from './types';
2
+ interface EditReport {
3
+ content: string;
4
+ noopEdits: HashlineEdit[];
5
+ deduplicatedEdits: number;
6
+ }
7
+ /**
8
+ * Apply all hashline edits to content and return a report.
9
+ * Edits are sorted bottom-up for correct line number handling.
10
+ */
11
+ export declare function applyHashlineEditsWithReport(content: string, edits: HashlineEdit[]): EditReport;
12
+ /**
13
+ * Convenience wrapper: apply edits and return the resulting content.
14
+ */
15
+ export declare function applyHashlineEdits(content: string, edits: HashlineEdit[]): string;
16
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { HashlineEdit } from './types';
2
+ import { type LineRef } from './validation';
3
+ /**
4
+ * Get the effective line number for sorting an edit operation.
5
+ * Returns -Infinity for unanchored operations (they go first/last).
6
+ */
7
+ export declare function getEditLineNumber(edit: HashlineEdit): number;
8
+ /**
9
+ * Collect all LINE#HASH references from a set of edits.
10
+ */
11
+ export declare function collectLineRefs(edits: HashlineEdit[]): LineRef[];
12
+ /**
13
+ * Detect overlapping ranges in replace edits.
14
+ * Returns an error message if overlaps found, null otherwise.
15
+ */
16
+ export declare function detectOverlappingRanges(edits: HashlineEdit[]): string | null;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Detect and strip hashline prefixes (N#XX|...) or diff + markers
3
+ * from an array of lines if ≥50% of non-empty lines have them.
4
+ */
5
+ export declare function stripLinePrefixes(lines: string[]): string[];
6
+ /**
7
+ * Convert string | string[] input to a string[], applying prefix stripping.
8
+ */
9
+ export declare function toNewLines(input: string | string[]): string[];
10
+ /**
11
+ * Restore the leading indentation from a template line onto a target line.
12
+ * Only restores if the trimmed content is DIFFERENT from the template's
13
+ * content (meaning a genuine edit was made but indentation was lost).
14
+ * If the trimmed content is the same, the user intentionally removed
15
+ * indentation, so we preserve their intent.
16
+ */
17
+ export declare function restoreLeadingIndent(templateLine: string, line: string): string;
18
+ /**
19
+ * Strip the anchor line echo from the beginning of inserted lines
20
+ * (for insert-after operations).
21
+ */
22
+ export declare function stripInsertAnchorEcho(anchorLine: string, newLines: string[]): string[];
23
+ /**
24
+ * Strip the anchor line echo from the end of inserted lines
25
+ * (for insert-before operations).
26
+ */
27
+ export declare function stripInsertBeforeEcho(anchorLine: string, newLines: string[]): string[];
28
+ /**
29
+ * Strip boundary echoes from both ends (for insert operations between lines).
30
+ */
31
+ export declare function stripInsertBoundaryEcho(afterLine: string, beforeLine: string, newLines: string[]): string[];
32
+ /**
33
+ * Strip surrounding context lines that leaked into replacement text
34
+ * (for range replace operations). Only strips non-blank echoes.
35
+ */
36
+ export declare function stripRangeBoundaryEcho(lines: string[], startLine: number, endLine: number, newLines: string[]): string[];
@@ -0,0 +1,14 @@
1
+ export interface FileTextEnvelope {
2
+ content: string;
3
+ hadBom: boolean;
4
+ lineEnding: '\n' | '\r\n';
5
+ }
6
+ /**
7
+ * Canonicalize file text: strip BOM, normalize line endings to LF.
8
+ * Returns the cleaned content plus an envelope for restoring later.
9
+ */
10
+ export declare function canonicalizeFileText(raw: string): FileTextEnvelope;
11
+ /**
12
+ * Restore original file text format from envelope (BOM, line endings).
13
+ */
14
+ export declare function restoreFileText(content: string, envelope: FileTextEnvelope): string;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Compute the 2-char hashline hash for a single line.
3
+ *
4
+ * - Significant lines (containing at least one letter or digit):
5
+ * stripped of leading/trailing whitespace → xxHash32 with seed 0.
6
+ * - Blank / whitespace-only lines: hashed with seed = lineNumber
7
+ * so identical blank lines at different positions get distinct IDs.
8
+ */
9
+ export declare function computeLineHash(lineNumber: number, content: string): string;
10
+ /** Format a single line as `LINE#HASH|content`. */
11
+ export declare function formatHashLine(lineNumber: number, content: string): string;
12
+ /** Format an entire file content string into hashline-prefixed lines. */
13
+ export declare function formatHashLines(content: string): string;
14
+ export interface StreamHashLinesOptions {
15
+ startLine?: number;
16
+ maxChunkLines?: number;
17
+ maxChunkBytes?: number;
18
+ }
19
+ /**
20
+ * Async generator that streams hashline-formatted chunks from a
21
+ * ReadableStream or AsyncIterable of UTF-8 bytes.
22
+ */
23
+ export declare function streamHashLinesFromUtf8(source: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>, options?: StreamHashLinesOptions): AsyncGenerator<string>;
24
+ /**
25
+ * Async generator that streams hashline-formatted chunks from
26
+ * sync or async line iterables.
27
+ */
28
+ export declare function streamHashLinesFromLines(lines: Iterable<string> | AsyncIterable<string>, options?: StreamHashLinesOptions): AsyncGenerator<string>;
@@ -0,0 +1,14 @@
1
+ interface ChunkFormatterOptions {
2
+ maxChunkLines: number;
3
+ maxChunkBytes: number;
4
+ }
5
+ interface ChunkFormatter {
6
+ push(line: string): string[];
7
+ flush(): string | undefined;
8
+ }
9
+ /**
10
+ * Buffered chunk formatter – accumulates formatted lines and yields
11
+ * chunks when either the line count or byte budget is exceeded.
12
+ */
13
+ export declare function createHashlineChunkFormatter(options: ChunkFormatterOptions): ChunkFormatter;
14
+ export {};
@@ -0,0 +1,17 @@
1
+ import type { RawHashlineEdit } from './normalize-edits';
2
+ interface ExecuteArgs {
3
+ filePath: string;
4
+ delete?: boolean;
5
+ rename?: string;
6
+ edits?: RawHashlineEdit[];
7
+ }
8
+ interface ExecuteContext {
9
+ sessionID?: string;
10
+ callID?: string;
11
+ metadata?: (data: Record<string, unknown>) => void;
12
+ }
13
+ /**
14
+ * Main entry point for hashline edit execution.
15
+ */
16
+ export declare function executeHashlineEditTool(args: ExecuteArgs, context: ExecuteContext): Promise<string>;
17
+ export {};
@@ -0,0 +1,6 @@
1
+ export { HASHLINE_DICT, HASHLINE_OUTPUT_PATTERN, HASHLINE_REF_PATTERN, NIBBLE_STR, } from './constants';
2
+ export { applyHashlineEdits } from './edit-operations';
3
+ export { computeLineHash, formatHashLine, formatHashLines, streamHashLinesFromLines, streamHashLinesFromUtf8, } from './hash-computation';
4
+ export { createHashlineEditTool } from './tools';
5
+ export type { AppendEdit, HashlineEdit, PrependEdit, ReplaceEdit, } from './types';
6
+ export { type LineRef, parseLineRef, validateLineRef, } from './validation';
@@ -0,0 +1,12 @@
1
+ import type { HashlineEdit } from './types';
2
+ export interface RawHashlineEdit {
3
+ op?: string;
4
+ pos?: string;
5
+ end?: string;
6
+ lines?: string | string[] | null;
7
+ }
8
+ /**
9
+ * Normalize raw tool input into typed HashlineEdit objects.
10
+ * Validates required fields per operation type.
11
+ */
12
+ export declare function normalizeHashlineEdits(rawEdits: RawHashlineEdit[]): HashlineEdit[];
@@ -0,0 +1 @@
1
+ export declare const HASHLINE_EDIT_DESCRIPTION = "Surgical file editor using LINE#ID anchors from Read output.\n\n## Workflow\n1. Read file \u2192 output shows lines as `LINE#ID|content`\n2. Pick operation: replace, append, prepend\n3. Submit edits referencing LINE#ID anchors\n4. Re-read after editing to get updated LINE#IDs\n\n## Operations\n\n### replace \u2013 Replace line(s)\n- Single line: `{op:\"replace\", pos:\"LINE#ID\", lines:\"new content\"}`\n- Range: `{op:\"replace\", pos:\"START#ID\", end:\"END#ID\", lines:[\"line1\",\"line2\"]}`\n- Boundaries are inclusive; replaced with lines array\n\n### append \u2013 Insert after\n- After anchor: `{op:\"append\", pos:\"LINE#ID\", lines:\"inserted line\"}`\n- End of file: `{op:\"append\", lines:\"appended line\"}` (no pos)\n\n### prepend \u2013 Insert before\n- Before anchor: `{op:\"prepend\", pos:\"LINE#ID\", lines:\"inserted line\"}`\n- Start of file: `{op:\"prepend\", lines:\"prepended line\"}` (no pos)\n\n## LINE#ID Format\n`LINE` = 1-based line number, `ID` = 2-char hash from [ZPMQVRWSNKTXJBYH].\nExample: `42#VK` \u2192 line 42 with hash VK.\n\n## File Operations\n- Delete file: `{filePath:\"...\", delete:true}`\n- Rename/move: `{filePath:\"...\", rename:\"new/path\", edits:[...]}`\n- Create file: unanchored append/prepend creates missing files\n\n## Content Format\n- `lines` accepts a string (one line) or string[] (multiple lines)\n- Lines are split on real newlines in strings\n- null or [] = delete the line(s)\n\n## Rules\n1. Keep edits minimal \u2013 only change what's needed\n2. Preserve original formatting and indentation\n3. Prefer append/prepend for insertions over replace\n4. Don't submit no-op edits (replacement identical to original)\n5. Use structural lines as anchors (function defs, class defs, etc.)\n6. Never anchor to blank lines\n7. Copy LINE#ID references exactly from Read output\n8. Re-read file after hash mismatch errors";
@@ -0,0 +1,5 @@
1
+ import { type ToolDefinition } from '@opencode-ai/plugin/tool';
2
+ /**
3
+ * Factory that creates the hashline_edit tool definition.
4
+ */
5
+ export declare function createHashlineEditTool(): ToolDefinition;
@@ -0,0 +1,17 @@
1
+ export interface ReplaceEdit {
2
+ op: 'replace';
3
+ pos?: string;
4
+ end?: string;
5
+ lines: string | string[];
6
+ }
7
+ export interface AppendEdit {
8
+ op: 'append';
9
+ pos?: string;
10
+ lines: string | string[];
11
+ }
12
+ export interface PrependEdit {
13
+ op: 'prepend';
14
+ pos?: string;
15
+ lines: string | string[];
16
+ }
17
+ export type HashlineEdit = ReplaceEdit | AppendEdit | PrependEdit;
@@ -0,0 +1,35 @@
1
+ export interface LineRef {
2
+ line: number;
3
+ hash: string;
4
+ }
5
+ /**
6
+ * Normalize a LINE#HASH reference string.
7
+ * Handles prefixes like >>>, +/-, whitespace around #, and trailing |content.
8
+ */
9
+ export declare function normalizeLineRef(ref: string): string;
10
+ /** Parse a LINE#HASH string into a LineRef. Throws on invalid format. */
11
+ export declare function parseLineRef(ref: string): LineRef;
12
+ /**
13
+ * Validate that a LineRef matches the actual file content.
14
+ * Throws HashlineMismatchError if the hash doesn't match.
15
+ */
16
+ export declare function validateLineRef(lines: string[], ref: LineRef | string): void;
17
+ /**
18
+ * Batch-validate multiple LineRefs. Collects all mismatches before
19
+ * throwing a single error. Handles parse failures gracefully by
20
+ * trying to suggest the correct line number.
21
+ */
22
+ export declare function validateLineRefs(lines: string[], refs: (LineRef | string)[]): void;
23
+ /**
24
+ * Scan all lines to find where a given hash actually appears.
25
+ * Returns the line number, or undefined if not found.
26
+ */
27
+ export declare function suggestLineForHash(ref: LineRef, lines: string[]): number | undefined;
28
+ /**
29
+ * Error thrown when hash validation fails, containing
30
+ * remapping information for recovery.
31
+ */
32
+ export declare class HashlineMismatchError extends Error {
33
+ readonly remaps: Map<string, string>;
34
+ constructor(message: string, remaps: Map<string, string>);
35
+ }
@@ -1,4 +1,5 @@
1
1
  export { ast_grep_replace, ast_grep_search } from './ast-grep';
2
2
  export { createBackgroundTools } from './background';
3
3
  export { grep } from './grep';
4
+ export { createHashlineEditTool } from './hashline-edit';
4
5
  export { lsp_diagnostics, lsp_find_references, lsp_goto_definition, lsp_rename, lspManager, } from './lsp';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frenchtoastman/oh-my-groundcontrol",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Lightweight agent orchestration plugin for OpenCode - a slimmed-down fork of oh-my-opencode",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -53,12 +53,14 @@
53
53
  "@modelcontextprotocol/sdk": "^1.26.0",
54
54
  "@opencode-ai/plugin": "^1.2.6",
55
55
  "@opencode-ai/sdk": "^1.2.6",
56
+ "diff": "^8.0.3",
56
57
  "vscode-jsonrpc": "^8.2.0",
57
58
  "vscode-languageserver-protocol": "^3.17.5",
58
59
  "zod": "^4.3.6"
59
60
  },
60
61
  "devDependencies": {
61
62
  "@biomejs/biome": "2.4.2",
63
+ "@types/diff": "^8.0.0",
62
64
  "bun-types": "1.3.9",
63
65
  "typescript": "^5.9.3"
64
66
  },