@agimon-ai/doompi-hashline 0.0.1-alpha.41 → 0.0.1-alpha.44
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/package.json +2 -2
- package/dist/files.cjs +0 -1
- package/dist/files.d.cts +0 -2
- package/dist/files.d.mts +0 -2
- package/dist/files.mjs +0 -1
- package/dist/index.cjs +0 -1
- package/dist/index.d.cts +0 -3
- package/dist/index.d.mts +0 -3
- package/dist/index.mjs +0 -1
- package/dist/services/files/index.cjs +0 -2
- package/dist/services/files/index.cjs.map +0 -1
- package/dist/services/files/index.d.cts +0 -11
- package/dist/services/files/index.d.cts.map +0 -1
- package/dist/services/files/index.d.mts +0 -11
- package/dist/services/files/index.d.mts.map +0 -1
- package/dist/services/files/index.mjs +0 -2
- package/dist/services/files/index.mjs.map +0 -1
- package/dist/services/hashline/index.cjs +0 -11
- package/dist/services/hashline/index.cjs.map +0 -1
- package/dist/services/hashline/index.d.cts +0 -20
- package/dist/services/hashline/index.d.cts.map +0 -1
- package/dist/services/hashline/index.d.mts +0 -20
- package/dist/services/hashline/index.d.mts.map +0 -1
- package/dist/services/hashline/index.mjs +0 -11
- package/dist/services/hashline/index.mjs.map +0 -1
- package/dist/types/hashline.d.cts +0 -33
- package/dist/types/hashline.d.cts.map +0 -1
- package/dist/types/hashline.d.mts +0 -33
- package/dist/types/hashline.d.mts.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/doompi-hashline",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.44",
|
|
4
4
|
"description": "Shared snapshot-bound file tags and line anchors for DoomPi tools.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
23
|
"url": "git+https://github.com/AgiFlow/doompi.git",
|
|
24
|
-
"directory": "packages/
|
|
24
|
+
"directory": "packages/utils/doompi-hashline"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"dist"
|
package/dist/files.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/files/index.cjs");exports.computeFileTag=e.computeFileTag,exports.decodeUtf8=e.decodeUtf8,exports.displayPath=e.displayPath,exports.isWritableFile=e.isWritableFile,exports.resolveInputPath=e.resolveInputPath,exports.resolveReadInputPath=e.resolveReadInputPath;
|
package/dist/files.d.cts
DELETED
package/dist/files.d.mts
DELETED
package/dist/files.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{computeFileTag as e,decodeUtf8 as t,displayPath as n,isWritableFile as r,resolveInputPath as i,resolveReadInputPath as a}from"./services/files/index.mjs";export{e as computeFileTag,t as decodeUtf8,n as displayPath,r as isWritableFile,i as resolveInputPath,a as resolveReadInputPath};
|
package/dist/index.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/hashline/index.cjs");exports.applyHashlineEdits=e.applyHashlineEdits,exports.formatFileHeader=e.formatFileHeader,exports.formatTaggedLine=e.formatTaggedLine,exports.formatTaggedLines=e.formatTaggedLines,exports.hashLine=e.hashLine,exports.normalizeFileTag=e.normalizeFileTag,exports.normalizeToLf=e.normalizeToLf,exports.parseFileHeader=e.parseFileHeader,exports.parseLineAnchor=e.parseLineAnchor,exports.parseTaggedLine=e.parseTaggedLine,exports.splitLines=e.splitLines,exports.stripBom=e.stripBom;
|
package/dist/index.d.cts
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { AppliedHashlineEdits, FileHeader, HashlineRangeInput, LineAnchor, ParsedTaggedLine, PreparedHashlineEdit, TaggedLineMarker, TaggedLinePrefix } from "./types/hashline.cjs";
|
|
2
|
-
import { applyHashlineEdits, formatFileHeader, formatTaggedLine, formatTaggedLines, hashLine, normalizeFileTag, normalizeToLf, parseFileHeader, parseLineAnchor, parseTaggedLine, splitLines, stripBom } from "./services/hashline/index.cjs";
|
|
3
|
-
export { type AppliedHashlineEdits, type FileHeader, type HashlineRangeInput, type LineAnchor, type ParsedTaggedLine, type PreparedHashlineEdit, type TaggedLineMarker, type TaggedLinePrefix, applyHashlineEdits, formatFileHeader, formatTaggedLine, formatTaggedLines, hashLine, normalizeFileTag, normalizeToLf, parseFileHeader, parseLineAnchor, parseTaggedLine, splitLines, stripBom };
|
package/dist/index.d.mts
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { AppliedHashlineEdits, FileHeader, HashlineRangeInput, LineAnchor, ParsedTaggedLine, PreparedHashlineEdit, TaggedLineMarker, TaggedLinePrefix } from "./types/hashline.mjs";
|
|
2
|
-
import { applyHashlineEdits, formatFileHeader, formatTaggedLine, formatTaggedLines, hashLine, normalizeFileTag, normalizeToLf, parseFileHeader, parseLineAnchor, parseTaggedLine, splitLines, stripBom } from "./services/hashline/index.mjs";
|
|
3
|
-
export { type AppliedHashlineEdits, type FileHeader, type HashlineRangeInput, type LineAnchor, type ParsedTaggedLine, type PreparedHashlineEdit, type TaggedLineMarker, type TaggedLinePrefix, applyHashlineEdits, formatFileHeader, formatTaggedLine, formatTaggedLines, hashLine, normalizeFileTag, normalizeToLf, parseFileHeader, parseLineAnchor, parseTaggedLine, splitLines, stripBom };
|
package/dist/index.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{applyHashlineEdits as e,formatFileHeader as t,formatTaggedLine as n,formatTaggedLines as r,hashLine as i,normalizeFileTag as a,normalizeToLf as o,parseFileHeader as s,parseLineAnchor as c,parseTaggedLine as l,splitLines as u,stripBom as d}from"./services/hashline/index.mjs";export{e as applyHashlineEdits,t as formatFileHeader,n as formatTaggedLine,r as formatTaggedLines,i as hashLine,a as normalizeFileTag,o as normalizeToLf,s as parseFileHeader,c as parseLineAnchor,l as parseTaggedLine,u as splitLines,d as stripBom};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
let e=require("node:crypto"),t=require("node:fs"),n=require("node:fs/promises"),r=require("node:os"),i=require("node:path"),a=require("node:url");const o=/[\u00A0\u2000-\u200A\u202F\u205F\u3000]/gu;function s(t){return(0,e.createHash)(`sha256`).update(t).digest(`base64url`).slice(0,8)}function c(e,t){try{return new TextDecoder(`utf-8`,{fatal:!0}).decode(e)}catch(e){throw Error(`Cannot use hashline tools on ${t}: the file is not valid UTF-8.`,{cause:e})}}async function l(e){return(0,n.access)(e,t.constants.W_OK).then(()=>!0,()=>!1)}function u(e,t){let n=e.replace(o,` `);return n.startsWith(`@`)&&(n=n.slice(1)),process.platform===`win32`&&(n=m(n)),n===`~`?n=(0,r.homedir)():n.startsWith(`~${i.sep}`)?n=(0,i.resolve)((0,r.homedir)(),n.slice(2)):n.startsWith(`file://`)&&(n=(0,a.fileURLToPath)(n)),(0,i.isAbsolute)(n)?(0,i.resolve)(n):(0,i.resolve)(t,n)}async function d(e,t){let n=u(e,t);if(await p(n))return n;let r=[n.replace(/ (AM|PM)\./giu,` $1.`),n.normalize(`NFD`),n.replaceAll(`'`,`’`),n.normalize(`NFD`).replaceAll(`'`,`’`)];for(let e of r)if(e!==n&&await p(e))return e;return n}function f(e,t){let n=(0,i.relative)(t,e),r=(n!==``&&n!==`..`&&!n.startsWith(`..${i.sep}`)&&!(0,i.isAbsolute)(n)?n:e).split(i.sep).join(`/`);return r===`~`||r.startsWith(`~/`)?`./${r}`:r}async function p(e){return(0,n.access)(e).then(()=>!0,()=>!1)}function m(e){if(!e.startsWith(`/`)||e.startsWith(`//`)||e.includes(`\\`))return e;let t=/^\/(?:mnt\/|cygdrive\/)?([a-z])(?:\/(.*))?$/iu.exec(e);if(!t?.[1])return e;let n=t[2]?.replaceAll(`/`,`\\`);return`${t[1].toUpperCase()}:\\${n??``}`}exports.computeFileTag=s,exports.decodeUtf8=c,exports.displayPath=f,exports.isWritableFile=l,exports.resolveInputPath=u,exports.resolveReadInputPath=d;
|
|
2
|
-
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["createHash","access","constants","homedir","sep","resolve","fileURLToPath","isAbsolute","relative"],"sources":["../../../src/services/files/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { constants } from 'node:fs';\nimport { access } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { isAbsolute, relative, resolve, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/gu;\nconst NARROW_NO_BREAK_SPACE = '\\u202f';\n\nexport function computeFileTag(bytes: Uint8Array): string {\n return createHash('sha256').update(bytes).digest('base64url').slice(0, 8);\n}\n\nexport function decodeUtf8(bytes: Uint8Array, path: string): string {\n try {\n return new TextDecoder('utf-8', { fatal: true }).decode(bytes);\n } catch (error) {\n throw new Error(`Cannot use hashline tools on ${path}: the file is not valid UTF-8.`, { cause: error });\n }\n}\n\n/** Return whether the current process can edit an existing file. */\nexport async function isWritableFile(path: string): Promise<boolean> {\n return access(path, constants.W_OK).then(\n () => true,\n () => false,\n );\n}\n\nexport function resolveInputPath(input: string, cwd: string): string {\n let path = input.replace(UNICODE_SPACES, ' ');\n if (path.startsWith('@')) path = path.slice(1);\n if (process.platform === 'win32') path = normalizeWindowsShellPath(path);\n if (path === '~') path = homedir();\n else if (path.startsWith(`~${sep}`)) path = resolve(homedir(), path.slice(2));\n else if (path.startsWith('file://')) path = fileURLToPath(path);\n return isAbsolute(path) ? resolve(path) : resolve(cwd, path);\n}\n\n/** Resolve the same existing-file variants as Pi's native read tool. */\nexport async function resolveReadInputPath(input: string, cwd: string): Promise<string> {\n const resolved = resolveInputPath(input, cwd);\n if (await pathExists(resolved)) return resolved;\n\n const variants = [\n resolved.replace(/ (AM|PM)\\./giu, `${NARROW_NO_BREAK_SPACE}$1.`),\n resolved.normalize('NFD'),\n resolved.replaceAll(\"'\", '\\u2019'),\n resolved.normalize('NFD').replaceAll(\"'\", '\\u2019'),\n ];\n for (const candidate of variants) {\n if (candidate !== resolved && (await pathExists(candidate))) return candidate;\n }\n return resolved;\n}\n\nexport function displayPath(absolutePath: string, cwd: string): string {\n const path = relative(cwd, absolutePath);\n const display =\n path !== '' && path !== '..' && !path.startsWith(`..${sep}`) && !isAbsolute(path) ? path : absolutePath;\n const portable = display.split(sep).join('/');\n return portable === '~' || portable.startsWith('~/') ? `./${portable}` : portable;\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n return access(path).then(\n () => true,\n () => false,\n );\n}\n\nfunction normalizeWindowsShellPath(path: string): string {\n if (!path.startsWith('/') || path.startsWith('//') || path.includes('\\\\')) return path;\n const match = /^\\/(?:mnt\\/|cygdrive\\/)?([a-z])(?:\\/(.*))?$/iu.exec(path);\n if (!match?.[1]) return path;\n const suffix = match[2]?.replaceAll('/', '\\\\');\n return `${match[1].toUpperCase()}:\\\\${suffix ?? ''}`;\n}\n"],"mappings":"kJAOA,MAAM,EAAiB,4CAGvB,SAAgB,EAAe,EAA2B,CACxD,OAAA,EAAOA,EAAAA,WAAAA,CAAW,QAAQ,CAAC,CAAC,OAAO,CAAK,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,EAAG,CAAC,CAC1E,CAEA,SAAgB,EAAW,EAAmB,EAAsB,CAClE,GAAI,CACF,OAAO,IAAI,YAAY,QAAS,CAAE,MAAO,EAAK,CAAC,CAAC,CAAC,OAAO,CAAK,CAC/D,OAAS,EAAO,CACd,MAAU,MAAM,gCAAgC,EAAK,gCAAiC,CAAE,MAAO,CAAM,CAAC,CACxG,CACF,CAGA,eAAsB,EAAe,EAAgC,CACnE,OAAA,EAAOC,EAAAA,OAAAA,CAAO,EAAMC,EAAAA,UAAU,IAAI,CAAC,CAAC,SAC5B,OACA,EACR,CACF,CAEA,SAAgB,EAAiB,EAAe,EAAqB,CACnE,IAAI,EAAO,EAAM,QAAQ,EAAgB,GAAG,EAM5C,OALI,EAAK,WAAW,GAAG,IAAG,EAAO,EAAK,MAAM,CAAC,GACzC,QAAQ,WAAa,UAAS,EAAO,EAA0B,CAAI,GACnE,IAAS,IAAK,GAAA,EAAOC,EAAAA,QAAAA,CAAQ,EACxB,EAAK,WAAW,IAAIC,EAAAA,KAAK,EAAG,GAAA,EAAOC,EAAAA,QAAAA,EAAAA,EAAQF,EAAAA,QAAAA,CAAQ,EAAG,EAAK,MAAM,CAAC,CAAC,EACnE,EAAK,WAAW,SAAS,IAAG,GAAA,EAAOG,EAAAA,cAAAA,CAAc,CAAI,IAC9D,EAAOC,EAAAA,WAAAA,CAAW,CAAI,GAAA,EAAIF,EAAAA,QAAAA,CAAQ,CAAI,GAAA,EAAIA,EAAAA,QAAAA,CAAQ,EAAK,CAAI,CAC7D,CAGA,eAAsB,EAAqB,EAAe,EAA8B,CACtF,IAAM,EAAW,EAAiB,EAAO,CAAG,EAC5C,GAAI,MAAM,EAAW,CAAQ,EAAG,OAAO,EAEvC,IAAM,EAAW,CACf,EAAS,QAAQ,gBAAiB,MAA6B,EAC/D,EAAS,UAAU,KAAK,EACxB,EAAS,WAAW,IAAK,GAAQ,EACjC,EAAS,UAAU,KAAK,CAAC,CAAC,WAAW,IAAK,GAAQ,CACpD,EACA,IAAK,IAAM,KAAa,EACtB,GAAI,IAAc,GAAa,MAAM,EAAW,CAAS,EAAI,OAAO,EAEtE,OAAO,CACT,CAEA,SAAgB,EAAY,EAAsB,EAAqB,CACrE,IAAM,GAAA,EAAOG,EAAAA,SAAAA,CAAS,EAAK,CAAY,EAGjC,GADJ,IAAS,IAAM,IAAS,MAAQ,CAAC,EAAK,WAAW,KAAKJ,EAAAA,KAAK,GAAK,EAAA,EAACG,EAAAA,WAAAA,CAAW,CAAI,EAAI,EAAO,EAAA,CACpE,MAAMH,EAAAA,GAAG,CAAC,CAAC,KAAK,GAAG,EAC5C,OAAO,IAAa,KAAO,EAAS,WAAW,IAAI,EAAI,KAAK,IAAa,CAC3E,CAEA,eAAe,EAAW,EAAgC,CACxD,OAAA,EAAOH,EAAAA,OAAAA,CAAO,CAAI,CAAC,CAAC,SACZ,OACA,EACR,CACF,CAEA,SAAS,EAA0B,EAAsB,CACvD,GAAI,CAAC,EAAK,WAAW,GAAG,GAAK,EAAK,WAAW,IAAI,GAAK,EAAK,SAAS,IAAI,EAAG,OAAO,EAClF,IAAM,EAAQ,gDAAgD,KAAK,CAAI,EACvE,GAAI,CAAC,IAAQ,GAAI,OAAO,EACxB,IAAM,EAAS,EAAM,EAAE,EAAE,WAAW,IAAK,IAAI,EAC7C,MAAO,GAAG,EAAM,EAAE,CAAC,YAAY,EAAE,KAAK,GAAU,IAClD"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
//#region src/services/files/index.d.ts
|
|
2
|
-
export declare function computeFileTag(bytes: Uint8Array): string;
|
|
3
|
-
export declare function decodeUtf8(bytes: Uint8Array, path: string): string;
|
|
4
|
-
/** Return whether the current process can edit an existing file. */
|
|
5
|
-
export declare function isWritableFile(path: string): Promise<boolean>;
|
|
6
|
-
export declare function resolveInputPath(input: string, cwd: string): string;
|
|
7
|
-
/** Resolve the same existing-file variants as Pi's native read tool. */
|
|
8
|
-
export declare function resolveReadInputPath(input: string, cwd: string): Promise<string>;
|
|
9
|
-
export declare function displayPath(absolutePath: string, cwd: string): string;
|
|
10
|
-
//#endregion
|
|
11
|
-
//# sourceMappingURL=index.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/services/files/index.ts"],"mappings":";wBAUgB,eAAe,OAAO;wBAItB,WAAW,OAAO,YAAY;;wBASxB,eAAe,eAAe;wBAOpC,iBAAiB,eAAe;;wBAW1B,qBAAqB,eAAe,cAAc;wBAgBxD,YAAY,sBAAsB"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
//#region src/services/files/index.d.ts
|
|
2
|
-
export declare function computeFileTag(bytes: Uint8Array): string;
|
|
3
|
-
export declare function decodeUtf8(bytes: Uint8Array, path: string): string;
|
|
4
|
-
/** Return whether the current process can edit an existing file. */
|
|
5
|
-
export declare function isWritableFile(path: string): Promise<boolean>;
|
|
6
|
-
export declare function resolveInputPath(input: string, cwd: string): string;
|
|
7
|
-
/** Resolve the same existing-file variants as Pi's native read tool. */
|
|
8
|
-
export declare function resolveReadInputPath(input: string, cwd: string): Promise<string>;
|
|
9
|
-
export declare function displayPath(absolutePath: string, cwd: string): string;
|
|
10
|
-
//#endregion
|
|
11
|
-
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/files/index.ts"],"mappings":";wBAUgB,eAAe,OAAO;wBAItB,WAAW,OAAO,YAAY;;wBASxB,eAAe,eAAe;wBAOpC,iBAAiB,eAAe;;wBAW1B,qBAAqB,eAAe,cAAc;wBAgBxD,YAAY,sBAAsB"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{createHash as e}from"node:crypto";import{constants as t}from"node:fs";import{access as n}from"node:fs/promises";import{homedir as r}from"node:os";import{isAbsolute as i,relative as a,resolve as o,sep as s}from"node:path";import{fileURLToPath as c}from"node:url";const l=/[\u00A0\u2000-\u200A\u202F\u205F\u3000]/gu;function u(t){return e(`sha256`).update(t).digest(`base64url`).slice(0,8)}function d(e,t){try{return new TextDecoder(`utf-8`,{fatal:!0}).decode(e)}catch(e){throw Error(`Cannot use hashline tools on ${t}: the file is not valid UTF-8.`,{cause:e})}}async function f(e){return n(e,t.W_OK).then(()=>!0,()=>!1)}function p(e,t){let n=e.replace(l,` `);return n.startsWith(`@`)&&(n=n.slice(1)),process.platform===`win32`&&(n=_(n)),n===`~`?n=r():n.startsWith(`~${s}`)?n=o(r(),n.slice(2)):n.startsWith(`file://`)&&(n=c(n)),i(n)?o(n):o(t,n)}async function m(e,t){let n=p(e,t);if(await g(n))return n;let r=[n.replace(/ (AM|PM)\./giu,` $1.`),n.normalize(`NFD`),n.replaceAll(`'`,`’`),n.normalize(`NFD`).replaceAll(`'`,`’`)];for(let e of r)if(e!==n&&await g(e))return e;return n}function h(e,t){let n=a(t,e),r=(n!==``&&n!==`..`&&!n.startsWith(`..${s}`)&&!i(n)?n:e).split(s).join(`/`);return r===`~`||r.startsWith(`~/`)?`./${r}`:r}async function g(e){return n(e).then(()=>!0,()=>!1)}function _(e){if(!e.startsWith(`/`)||e.startsWith(`//`)||e.includes(`\\`))return e;let t=/^\/(?:mnt\/|cygdrive\/)?([a-z])(?:\/(.*))?$/iu.exec(e);if(!t?.[1])return e;let n=t[2]?.replaceAll(`/`,`\\`);return`${t[1].toUpperCase()}:\\${n??``}`}export{u as computeFileTag,d as decodeUtf8,h as displayPath,f as isWritableFile,p as resolveInputPath,m as resolveReadInputPath};
|
|
2
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/services/files/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { constants } from 'node:fs';\nimport { access } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { isAbsolute, relative, resolve, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/gu;\nconst NARROW_NO_BREAK_SPACE = '\\u202f';\n\nexport function computeFileTag(bytes: Uint8Array): string {\n return createHash('sha256').update(bytes).digest('base64url').slice(0, 8);\n}\n\nexport function decodeUtf8(bytes: Uint8Array, path: string): string {\n try {\n return new TextDecoder('utf-8', { fatal: true }).decode(bytes);\n } catch (error) {\n throw new Error(`Cannot use hashline tools on ${path}: the file is not valid UTF-8.`, { cause: error });\n }\n}\n\n/** Return whether the current process can edit an existing file. */\nexport async function isWritableFile(path: string): Promise<boolean> {\n return access(path, constants.W_OK).then(\n () => true,\n () => false,\n );\n}\n\nexport function resolveInputPath(input: string, cwd: string): string {\n let path = input.replace(UNICODE_SPACES, ' ');\n if (path.startsWith('@')) path = path.slice(1);\n if (process.platform === 'win32') path = normalizeWindowsShellPath(path);\n if (path === '~') path = homedir();\n else if (path.startsWith(`~${sep}`)) path = resolve(homedir(), path.slice(2));\n else if (path.startsWith('file://')) path = fileURLToPath(path);\n return isAbsolute(path) ? resolve(path) : resolve(cwd, path);\n}\n\n/** Resolve the same existing-file variants as Pi's native read tool. */\nexport async function resolveReadInputPath(input: string, cwd: string): Promise<string> {\n const resolved = resolveInputPath(input, cwd);\n if (await pathExists(resolved)) return resolved;\n\n const variants = [\n resolved.replace(/ (AM|PM)\\./giu, `${NARROW_NO_BREAK_SPACE}$1.`),\n resolved.normalize('NFD'),\n resolved.replaceAll(\"'\", '\\u2019'),\n resolved.normalize('NFD').replaceAll(\"'\", '\\u2019'),\n ];\n for (const candidate of variants) {\n if (candidate !== resolved && (await pathExists(candidate))) return candidate;\n }\n return resolved;\n}\n\nexport function displayPath(absolutePath: string, cwd: string): string {\n const path = relative(cwd, absolutePath);\n const display =\n path !== '' && path !== '..' && !path.startsWith(`..${sep}`) && !isAbsolute(path) ? path : absolutePath;\n const portable = display.split(sep).join('/');\n return portable === '~' || portable.startsWith('~/') ? `./${portable}` : portable;\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n return access(path).then(\n () => true,\n () => false,\n );\n}\n\nfunction normalizeWindowsShellPath(path: string): string {\n if (!path.startsWith('/') || path.startsWith('//') || path.includes('\\\\')) return path;\n const match = /^\\/(?:mnt\\/|cygdrive\\/)?([a-z])(?:\\/(.*))?$/iu.exec(path);\n if (!match?.[1]) return path;\n const suffix = match[2]?.replaceAll('/', '\\\\');\n return `${match[1].toUpperCase()}:\\\\${suffix ?? ''}`;\n}\n"],"mappings":"6QAOA,MAAM,EAAiB,4CAGvB,SAAgB,EAAe,EAA2B,CACxD,OAAO,EAAW,QAAQ,CAAC,CAAC,OAAO,CAAK,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,EAAG,CAAC,CAC1E,CAEA,SAAgB,EAAW,EAAmB,EAAsB,CAClE,GAAI,CACF,OAAO,IAAI,YAAY,QAAS,CAAE,MAAO,EAAK,CAAC,CAAC,CAAC,OAAO,CAAK,CAC/D,OAAS,EAAO,CACd,MAAU,MAAM,gCAAgC,EAAK,gCAAiC,CAAE,MAAO,CAAM,CAAC,CACxG,CACF,CAGA,eAAsB,EAAe,EAAgC,CACnE,OAAO,EAAO,EAAM,EAAU,IAAI,CAAC,CAAC,SAC5B,OACA,EACR,CACF,CAEA,SAAgB,EAAiB,EAAe,EAAqB,CACnE,IAAI,EAAO,EAAM,QAAQ,EAAgB,GAAG,EAM5C,OALI,EAAK,WAAW,GAAG,IAAG,EAAO,EAAK,MAAM,CAAC,GACzC,QAAQ,WAAa,UAAS,EAAO,EAA0B,CAAI,GACnE,IAAS,IAAK,EAAO,EAAQ,EACxB,EAAK,WAAW,IAAI,GAAK,EAAG,EAAO,EAAQ,EAAQ,EAAG,EAAK,MAAM,CAAC,CAAC,EACnE,EAAK,WAAW,SAAS,IAAG,EAAO,EAAc,CAAI,GACvD,EAAW,CAAI,EAAI,EAAQ,CAAI,EAAI,EAAQ,EAAK,CAAI,CAC7D,CAGA,eAAsB,EAAqB,EAAe,EAA8B,CACtF,IAAM,EAAW,EAAiB,EAAO,CAAG,EAC5C,GAAI,MAAM,EAAW,CAAQ,EAAG,OAAO,EAEvC,IAAM,EAAW,CACf,EAAS,QAAQ,gBAAiB,MAA6B,EAC/D,EAAS,UAAU,KAAK,EACxB,EAAS,WAAW,IAAK,GAAQ,EACjC,EAAS,UAAU,KAAK,CAAC,CAAC,WAAW,IAAK,GAAQ,CACpD,EACA,IAAK,IAAM,KAAa,EACtB,GAAI,IAAc,GAAa,MAAM,EAAW,CAAS,EAAI,OAAO,EAEtE,OAAO,CACT,CAEA,SAAgB,EAAY,EAAsB,EAAqB,CACrE,IAAM,EAAO,EAAS,EAAK,CAAY,EAGjC,GADJ,IAAS,IAAM,IAAS,MAAQ,CAAC,EAAK,WAAW,KAAK,GAAK,GAAK,CAAC,EAAW,CAAI,EAAI,EAAO,EAAA,CACpE,MAAM,CAAG,CAAC,CAAC,KAAK,GAAG,EAC5C,OAAO,IAAa,KAAO,EAAS,WAAW,IAAI,EAAI,KAAK,IAAa,CAC3E,CAEA,eAAe,EAAW,EAAgC,CACxD,OAAO,EAAO,CAAI,CAAC,CAAC,SACZ,OACA,EACR,CACF,CAEA,SAAS,EAA0B,EAAsB,CACvD,GAAI,CAAC,EAAK,WAAW,GAAG,GAAK,EAAK,WAAW,IAAI,GAAK,EAAK,SAAS,IAAI,EAAG,OAAO,EAClF,IAAM,EAAQ,gDAAgD,KAAK,CAAI,EACvE,GAAI,CAAC,IAAQ,GAAI,OAAO,EACxB,IAAM,EAAS,EAAM,EAAE,EAAE,WAAW,IAAK,IAAI,EAC7C,MAAO,GAAG,EAAM,EAAE,CAAC,YAAY,EAAE,KAAK,GAAU,IAClD"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const e=26n*26n*26n,t=/^[A-Za-z0-9_-]{8}$/u,n=/^@file (.+)#([A-Za-z0-9_-]{8})$/u,r=/^(>> | {3})?(\d+)#[a-z]{3}\|(.*)$/u,i=/^\s*[>+-]*\s*(\d+)\s*[:#]\s*([a-zA-Z]{3})(?:\s*\|.*)?\s*$/u,a=/[ \t\n\r\v\f]/gu;function o(t){let n=new TextEncoder().encode(t.replace(a,``)),r=14695981039346656037n;for(let e of n)r^=BigInt(e),r=BigInt.asUintN(64,r*1099511628211n);let i=r%e,o=Array.from({length:3},()=>``);for(let e=o.length-1;e>=0;--e)o[e]=String.fromCharCode(97+Number(i%26n)),i/=26n;return o.join(``)}function s(e){return e.replace(/\r\n/gu,`
|
|
2
|
-
`).replace(/\r/gu,`
|
|
3
|
-
`)}function c(e){return e.charCodeAt(0)===65279?e.slice(1):e}function l(e){return s(c(e)).split(`
|
|
4
|
-
`)}function u(e){let n=e.trim(),r=n.lastIndexOf(`#`),i=r===-1?n:n.slice(r+1);if(!t.test(i))throw Error(`Invalid file hash: ${e}. Expected the eight-character tag from @file path#HASH.`);return i}function d(e,t){if(e.length===0||e.includes(`
|
|
5
|
-
`)||e.includes(`\r`))throw Error(`Invalid file header path. Expected one non-empty path without line breaks.`);return`@file ${e}#${u(t)}`}function f(e){let t=n.exec(e),r=t?.[1],i=t?.[2];return r===void 0||i===void 0?void 0:{path:r,tag:i}}function p(e,t,n=``,r=e){return y(t),`${n}${t}#${o(r)}|${e}`}function m(e,t=1){return e.map((e,n)=>p(e,t+n)).join(`
|
|
6
|
-
`)}function h(e){let t=r.exec(e),n=t?.[2],i=t?.[3];if(n===void 0||i===void 0)return;let a=Number.parseInt(n,10);if(!Number.isSafeInteger(a)||a<1)return;let o=v(t?.[1]);return o===void 0?{content:i,line:a}:{content:i,line:a,marker:o}}function g(e){if(e.includes(`
|
|
7
|
-
`)||e.includes(`\r`))throw Error(`Invalid line anchor: ${e}. Expected one anchor such as 5#abc, not a pasted multiline block.`);let t=i.exec(e);if(!t)throw Error(`Invalid line anchor: ${e}. Expected one anchor such as 5#abc from the latest read or grep result.`);let n=Number.parseInt(t[1]??``,10),r=t[2]?.toLowerCase();if(!Number.isSafeInteger(n)||n<1||r===void 0)throw Error(`Invalid line anchor: ${e}. Expected a positive line number and three letters, such as 5#abc.`);return{line:n,hash:r}}function _(e,t){let n=l(e),r=S(t.map(e=>b(e,n))).sort(C);w(r);let i=[...n];for(let e of[...r].reverse()){let t=e.to.line-e.from.line+1,n=e.content===null||e.content===``?[]:T(e.content);i.splice(e.from.line-1,t,...n)}return{content:i.join(`
|
|
8
|
-
`),edits:r}}function v(e){if(e===`>> `)return`match`;if(e===` `)return`context`}function y(e){if(!Number.isSafeInteger(e)||e<1)throw Error(`Invalid tagged line number: ${String(e)}. Expected a positive safe integer.`)}function b(e,t){let n=g(e.from),r=g(e.to);if(n.line>r.line)throw Error(`Invalid edit range ${e.from} to ${e.to}: the starting line follows the ending line.`);if(r.line>t.length)throw Error(`Invalid edit range ${e.from} to ${e.to}: the file has ${t.length} lines.`);return x(n,t),x(r,t),{from:n,to:r,content:e.content??null,source:e}}function x(e,t){let n=t[e.line-1];if(n===void 0)throw Error(`Line ${e.line} is outside the current file.`);let r=o(n);if(r!==e.hash)throw Error(`Stale line anchor ${e.line}#${e.hash}. Current anchor is ${e.line}#${r}. Re-read the file and retry.`)}function S(e){let t=new Map;for(let n of e){let e=JSON.stringify([n.from.line,n.from.hash,n.to.line,n.to.hash,n.content]);t.has(e)||t.set(e,n)}return[...t.values()]}function C(e,t){return e.from.line-t.from.line||e.to.line-t.to.line}function w(e){for(let t=1;t<e.length;t+=1){let n=e[t-1],r=e[t];if(n!==void 0&&r!==void 0&&r.from.line<=n.to.line)throw Error(`Overlapping edit ranges ${n.from.line}-${n.to.line} and ${r.from.line}-${r.to.line}. Merge them and retry.`)}}function T(e){let t=s(e),n=t.endsWith(`
|
|
9
|
-
`)?t.slice(0,-1):t;return n===``?[]:n.split(`
|
|
10
|
-
`)}exports.applyHashlineEdits=_,exports.formatFileHeader=d,exports.formatTaggedLine=p,exports.formatTaggedLines=m,exports.hashLine=o,exports.normalizeFileTag=u,exports.normalizeToLf=s,exports.parseFileHeader=f,exports.parseLineAnchor=g,exports.parseTaggedLine=h,exports.splitLines=l,exports.stripBom=c;
|
|
11
|
-
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../../../src/services/hashline/index.ts"],"sourcesContent":["import type {\n AppliedHashlineEdits,\n FileHeader,\n HashlineRangeInput,\n LineAnchor,\n ParsedTaggedLine,\n PreparedHashlineEdit,\n TaggedLineMarker,\n TaggedLinePrefix,\n} from '../../types/hashline';\n\nconst FNV_OFFSET_BASIS = 0xcbf29ce484222325n;\nconst FNV_PRIME = 0x100000001b3n;\nconst ANCHOR_SPACE = 26n * 26n * 26n;\nconst ASCII_A = 97;\nconst FILE_TAG_PATTERN = /^[A-Za-z0-9_-]{8}$/u;\nconst FILE_HEADER_PATTERN = /^@file (.+)#([A-Za-z0-9_-]{8})$/u;\nconst TAGGED_LINE_PATTERN = /^(>> | {3})?(\\d+)#[a-z]{3}\\|(.*)$/u;\nconst ANCHOR_PATTERN = /^\\s*[>+-]*\\s*(\\d+)\\s*[:#]\\s*([a-zA-Z]{3})(?:\\s*\\|.*)?\\s*$/u;\nconst ASCII_WHITESPACE = /[ \\t\\n\\r\\v\\f]/gu;\n\n/**\n * Return Phi's three-letter whitespace-insensitive FNV-1a64 line anchor.\n * Adapted from pulseaiclub/phi writetool under the MIT license.\n */\nexport function hashLine(line: string): string {\n const bytes = new TextEncoder().encode(line.replace(ASCII_WHITESPACE, ''));\n let hash = FNV_OFFSET_BASIS;\n for (const byte of bytes) {\n hash ^= BigInt(byte);\n hash = BigInt.asUintN(64, hash * FNV_PRIME);\n }\n\n let value = hash % ANCHOR_SPACE;\n const letters = Array.from({ length: 3 }, () => '');\n for (let index = letters.length - 1; index >= 0; index -= 1) {\n letters[index] = String.fromCharCode(ASCII_A + Number(value % 26n));\n value /= 26n;\n }\n return letters.join('');\n}\n\nexport function normalizeToLf(text: string): string {\n return text.replace(/\\r\\n/gu, '\\n').replace(/\\r/gu, '\\n');\n}\n\nexport function stripBom(text: string): string {\n return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n}\n\nexport function splitLines(text: string): string[] {\n return normalizeToLf(stripBom(text)).split('\\n');\n}\n\nexport function normalizeFileTag(value: string): string {\n const trimmed = value.trim();\n const hashIndex = trimmed.lastIndexOf('#');\n const tag = hashIndex === -1 ? trimmed : trimmed.slice(hashIndex + 1);\n if (!FILE_TAG_PATTERN.test(tag)) {\n throw new Error(`Invalid file hash: ${value}. Expected the eight-character tag from @file path#HASH.`);\n }\n return tag;\n}\n\nexport function formatFileHeader(path: string, tag: string): string {\n if (path.length === 0 || path.includes('\\n') || path.includes('\\r')) {\n throw new Error('Invalid file header path. Expected one non-empty path without line breaks.');\n }\n return `@file ${path}#${normalizeFileTag(tag)}`;\n}\n\nexport function parseFileHeader(value: string): FileHeader | undefined {\n const match = FILE_HEADER_PATTERN.exec(value);\n const path = match?.[1];\n const tag = match?.[2];\n return path === undefined || tag === undefined ? undefined : { path, tag };\n}\n\nexport function formatTaggedLine(\n line: string,\n lineNumber: number,\n prefix: TaggedLinePrefix = '',\n anchorSource = line,\n): string {\n assertLineNumber(lineNumber);\n return `${prefix}${lineNumber}#${hashLine(anchorSource)}|${line}`;\n}\n\nexport function formatTaggedLines(lines: readonly string[], firstLine = 1): string {\n return lines.map((line, index) => formatTaggedLine(line, firstLine + index)).join('\\n');\n}\n\nexport function parseTaggedLine(value: string): ParsedTaggedLine | undefined {\n const match = TAGGED_LINE_PATTERN.exec(value);\n const lineText = match?.[2];\n const content = match?.[3];\n if (lineText === undefined || content === undefined) return undefined;\n\n const line = Number.parseInt(lineText, 10);\n if (!Number.isSafeInteger(line) || line < 1) return undefined;\n\n const marker = taggedLineMarker(match?.[1]);\n return marker === undefined ? { content, line } : { content, line, marker };\n}\n\nexport function parseLineAnchor(value: string): LineAnchor {\n if (value.includes('\\n') || value.includes('\\r')) {\n throw new Error(`Invalid line anchor: ${value}. Expected one anchor such as 5#abc, not a pasted multiline block.`);\n }\n\n const match = ANCHOR_PATTERN.exec(value);\n if (!match) {\n throw new Error(\n `Invalid line anchor: ${value}. Expected one anchor such as 5#abc from the latest read or grep result.`,\n );\n }\n\n const line = Number.parseInt(match[1] ?? '', 10);\n const hash = match[2]?.toLowerCase();\n if (!Number.isSafeInteger(line) || line < 1 || hash === undefined) {\n throw new Error(`Invalid line anchor: ${value}. Expected a positive line number and three letters, such as 5#abc.`);\n }\n return { line, hash };\n}\n\nexport function applyHashlineEdits(\n originalContent: string,\n requestedEdits: readonly HashlineRangeInput[],\n): AppliedHashlineEdits {\n const lines = splitLines(originalContent);\n const validated = requestedEdits.map((edit) => validateEdit(edit, lines));\n const edits = deduplicateEdits(validated).sort(compareEdits);\n validateNoOverlaps(edits);\n\n const result = [...lines];\n for (const edit of [...edits].reverse()) {\n const deleteCount = edit.to.line - edit.from.line + 1;\n const replacements = edit.content === null || edit.content === '' ? [] : splitReplacement(edit.content);\n result.splice(edit.from.line - 1, deleteCount, ...replacements);\n }\n return { content: result.join('\\n'), edits };\n}\n\nfunction taggedLineMarker(prefix: string | undefined): TaggedLineMarker | undefined {\n if (prefix === '>> ') return 'match';\n if (prefix === ' ') return 'context';\n return undefined;\n}\n\nfunction assertLineNumber(line: number): void {\n if (!Number.isSafeInteger(line) || line < 1) {\n throw new Error(`Invalid tagged line number: ${String(line)}. Expected a positive safe integer.`);\n }\n}\n\nfunction validateEdit(edit: HashlineRangeInput, lines: readonly string[]): PreparedHashlineEdit {\n const from = parseLineAnchor(edit.from);\n const to = parseLineAnchor(edit.to);\n if (from.line > to.line) {\n throw new Error(`Invalid edit range ${edit.from} to ${edit.to}: the starting line follows the ending line.`);\n }\n if (to.line > lines.length) {\n throw new Error(`Invalid edit range ${edit.from} to ${edit.to}: the file has ${lines.length} lines.`);\n }\n\n validateAnchor(from, lines);\n validateAnchor(to, lines);\n return { from, to, content: edit.content ?? null, source: edit };\n}\n\nfunction validateAnchor(anchor: LineAnchor, lines: readonly string[]): void {\n const line = lines[anchor.line - 1];\n if (line === undefined) throw new Error(`Line ${anchor.line} is outside the current file.`);\n const currentHash = hashLine(line);\n if (currentHash !== anchor.hash) {\n throw new Error(\n `Stale line anchor ${anchor.line}#${anchor.hash}. Current anchor is ${anchor.line}#${currentHash}. Re-read the file and retry.`,\n );\n }\n}\n\nfunction deduplicateEdits(edits: readonly PreparedHashlineEdit[]): PreparedHashlineEdit[] {\n const unique = new Map<string, PreparedHashlineEdit>();\n for (const edit of edits) {\n const key = JSON.stringify([edit.from.line, edit.from.hash, edit.to.line, edit.to.hash, edit.content]);\n if (!unique.has(key)) unique.set(key, edit);\n }\n return [...unique.values()];\n}\n\nfunction compareEdits(left: PreparedHashlineEdit, right: PreparedHashlineEdit): number {\n return left.from.line - right.from.line || left.to.line - right.to.line;\n}\n\nfunction validateNoOverlaps(edits: readonly PreparedHashlineEdit[]): void {\n for (let index = 1; index < edits.length; index += 1) {\n const previous = edits[index - 1];\n const current = edits[index];\n if (previous !== undefined && current !== undefined && current.from.line <= previous.to.line) {\n throw new Error(\n `Overlapping edit ranges ${previous.from.line}-${previous.to.line} and ${current.from.line}-${current.to.line}. Merge them and retry.`,\n );\n }\n }\n}\n\nfunction splitReplacement(content: string): string[] {\n const normalized = normalizeToLf(content);\n const trimmed = normalized.endsWith('\\n') ? normalized.slice(0, -1) : normalized;\n return trimmed === '' ? [] : trimmed.split('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { AppliedHashlineEdits, FileHeader, HashlineRangeInput, LineAnchor, ParsedTaggedLine, TaggedLinePrefix } from "../../types/hashline.cjs";
|
|
2
|
-
//#region src/services/hashline/index.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* Return Phi's three-letter whitespace-insensitive FNV-1a64 line anchor.
|
|
5
|
-
* Adapted from pulseaiclub/phi writetool under the MIT license.
|
|
6
|
-
*/
|
|
7
|
-
export declare function hashLine(line: string): string;
|
|
8
|
-
export declare function normalizeToLf(text: string): string;
|
|
9
|
-
export declare function stripBom(text: string): string;
|
|
10
|
-
export declare function splitLines(text: string): string[];
|
|
11
|
-
export declare function normalizeFileTag(value: string): string;
|
|
12
|
-
export declare function formatFileHeader(path: string, tag: string): string;
|
|
13
|
-
export declare function parseFileHeader(value: string): FileHeader | undefined;
|
|
14
|
-
export declare function formatTaggedLine(line: string, lineNumber: number, prefix?: TaggedLinePrefix, anchorSource?: string): string;
|
|
15
|
-
export declare function formatTaggedLines(lines: readonly string[], firstLine?: number): string;
|
|
16
|
-
export declare function parseTaggedLine(value: string): ParsedTaggedLine | undefined;
|
|
17
|
-
export declare function parseLineAnchor(value: string): LineAnchor;
|
|
18
|
-
export declare function applyHashlineEdits(originalContent: string, requestedEdits: readonly HashlineRangeInput[]): AppliedHashlineEdits;
|
|
19
|
-
//#endregion
|
|
20
|
-
//# sourceMappingURL=index.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/services/hashline/index.ts"],"mappings":";;;;;;wBAyBgB,SAAS;wBAiBT,cAAc;wBAId,SAAS;wBAIT,WAAW;wBAIX,iBAAiB;wBAUjB,iBAAiB,cAAc;wBAO/B,gBAAgB,gBAAgB;wBAOhC,iBACd,cACA,oBACA,SAAQ,kBACR;wBAMc,kBAAkB,0BAA0B;wBAI5C,gBAAgB,gBAAgB;wBAahC,gBAAgB,gBAAgB;wBAoBhC,mBACd,yBACA,yBAAyB,uBACxB"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { AppliedHashlineEdits, FileHeader, HashlineRangeInput, LineAnchor, ParsedTaggedLine, TaggedLinePrefix } from "../../types/hashline.mjs";
|
|
2
|
-
//#region src/services/hashline/index.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* Return Phi's three-letter whitespace-insensitive FNV-1a64 line anchor.
|
|
5
|
-
* Adapted from pulseaiclub/phi writetool under the MIT license.
|
|
6
|
-
*/
|
|
7
|
-
export declare function hashLine(line: string): string;
|
|
8
|
-
export declare function normalizeToLf(text: string): string;
|
|
9
|
-
export declare function stripBom(text: string): string;
|
|
10
|
-
export declare function splitLines(text: string): string[];
|
|
11
|
-
export declare function normalizeFileTag(value: string): string;
|
|
12
|
-
export declare function formatFileHeader(path: string, tag: string): string;
|
|
13
|
-
export declare function parseFileHeader(value: string): FileHeader | undefined;
|
|
14
|
-
export declare function formatTaggedLine(line: string, lineNumber: number, prefix?: TaggedLinePrefix, anchorSource?: string): string;
|
|
15
|
-
export declare function formatTaggedLines(lines: readonly string[], firstLine?: number): string;
|
|
16
|
-
export declare function parseTaggedLine(value: string): ParsedTaggedLine | undefined;
|
|
17
|
-
export declare function parseLineAnchor(value: string): LineAnchor;
|
|
18
|
-
export declare function applyHashlineEdits(originalContent: string, requestedEdits: readonly HashlineRangeInput[]): AppliedHashlineEdits;
|
|
19
|
-
//#endregion
|
|
20
|
-
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/hashline/index.ts"],"mappings":";;;;;;wBAyBgB,SAAS;wBAiBT,cAAc;wBAId,SAAS;wBAIT,WAAW;wBAIX,iBAAiB;wBAUjB,iBAAiB,cAAc;wBAO/B,gBAAgB,gBAAgB;wBAOhC,iBACd,cACA,oBACA,SAAQ,kBACR;wBAMc,kBAAkB,0BAA0B;wBAI5C,gBAAgB,gBAAgB;wBAahC,gBAAgB,gBAAgB;wBAoBhC,mBACd,yBACA,yBAAyB,uBACxB"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const e=26n*26n*26n,t=/^[A-Za-z0-9_-]{8}$/u,n=/^@file (.+)#([A-Za-z0-9_-]{8})$/u,r=/^(>> | {3})?(\d+)#[a-z]{3}\|(.*)$/u,i=/^\s*[>+-]*\s*(\d+)\s*[:#]\s*([a-zA-Z]{3})(?:\s*\|.*)?\s*$/u,a=/[ \t\n\r\v\f]/gu;function o(t){let n=new TextEncoder().encode(t.replace(a,``)),r=14695981039346656037n;for(let e of n)r^=BigInt(e),r=BigInt.asUintN(64,r*1099511628211n);let i=r%e,o=Array.from({length:3},()=>``);for(let e=o.length-1;e>=0;--e)o[e]=String.fromCharCode(97+Number(i%26n)),i/=26n;return o.join(``)}function s(e){return e.replace(/\r\n/gu,`
|
|
2
|
-
`).replace(/\r/gu,`
|
|
3
|
-
`)}function c(e){return e.charCodeAt(0)===65279?e.slice(1):e}function l(e){return s(c(e)).split(`
|
|
4
|
-
`)}function u(e){let n=e.trim(),r=n.lastIndexOf(`#`),i=r===-1?n:n.slice(r+1);if(!t.test(i))throw Error(`Invalid file hash: ${e}. Expected the eight-character tag from @file path#HASH.`);return i}function d(e,t){if(e.length===0||e.includes(`
|
|
5
|
-
`)||e.includes(`\r`))throw Error(`Invalid file header path. Expected one non-empty path without line breaks.`);return`@file ${e}#${u(t)}`}function f(e){let t=n.exec(e),r=t?.[1],i=t?.[2];return r===void 0||i===void 0?void 0:{path:r,tag:i}}function p(e,t,n=``,r=e){return y(t),`${n}${t}#${o(r)}|${e}`}function m(e,t=1){return e.map((e,n)=>p(e,t+n)).join(`
|
|
6
|
-
`)}function h(e){let t=r.exec(e),n=t?.[2],i=t?.[3];if(n===void 0||i===void 0)return;let a=Number.parseInt(n,10);if(!Number.isSafeInteger(a)||a<1)return;let o=v(t?.[1]);return o===void 0?{content:i,line:a}:{content:i,line:a,marker:o}}function g(e){if(e.includes(`
|
|
7
|
-
`)||e.includes(`\r`))throw Error(`Invalid line anchor: ${e}. Expected one anchor such as 5#abc, not a pasted multiline block.`);let t=i.exec(e);if(!t)throw Error(`Invalid line anchor: ${e}. Expected one anchor such as 5#abc from the latest read or grep result.`);let n=Number.parseInt(t[1]??``,10),r=t[2]?.toLowerCase();if(!Number.isSafeInteger(n)||n<1||r===void 0)throw Error(`Invalid line anchor: ${e}. Expected a positive line number and three letters, such as 5#abc.`);return{line:n,hash:r}}function _(e,t){let n=l(e),r=S(t.map(e=>b(e,n))).sort(C);w(r);let i=[...n];for(let e of[...r].reverse()){let t=e.to.line-e.from.line+1,n=e.content===null||e.content===``?[]:T(e.content);i.splice(e.from.line-1,t,...n)}return{content:i.join(`
|
|
8
|
-
`),edits:r}}function v(e){if(e===`>> `)return`match`;if(e===` `)return`context`}function y(e){if(!Number.isSafeInteger(e)||e<1)throw Error(`Invalid tagged line number: ${String(e)}. Expected a positive safe integer.`)}function b(e,t){let n=g(e.from),r=g(e.to);if(n.line>r.line)throw Error(`Invalid edit range ${e.from} to ${e.to}: the starting line follows the ending line.`);if(r.line>t.length)throw Error(`Invalid edit range ${e.from} to ${e.to}: the file has ${t.length} lines.`);return x(n,t),x(r,t),{from:n,to:r,content:e.content??null,source:e}}function x(e,t){let n=t[e.line-1];if(n===void 0)throw Error(`Line ${e.line} is outside the current file.`);let r=o(n);if(r!==e.hash)throw Error(`Stale line anchor ${e.line}#${e.hash}. Current anchor is ${e.line}#${r}. Re-read the file and retry.`)}function S(e){let t=new Map;for(let n of e){let e=JSON.stringify([n.from.line,n.from.hash,n.to.line,n.to.hash,n.content]);t.has(e)||t.set(e,n)}return[...t.values()]}function C(e,t){return e.from.line-t.from.line||e.to.line-t.to.line}function w(e){for(let t=1;t<e.length;t+=1){let n=e[t-1],r=e[t];if(n!==void 0&&r!==void 0&&r.from.line<=n.to.line)throw Error(`Overlapping edit ranges ${n.from.line}-${n.to.line} and ${r.from.line}-${r.to.line}. Merge them and retry.`)}}function T(e){let t=s(e),n=t.endsWith(`
|
|
9
|
-
`)?t.slice(0,-1):t;return n===``?[]:n.split(`
|
|
10
|
-
`)}export{_ as applyHashlineEdits,d as formatFileHeader,p as formatTaggedLine,m as formatTaggedLines,o as hashLine,u as normalizeFileTag,s as normalizeToLf,f as parseFileHeader,g as parseLineAnchor,h as parseTaggedLine,l as splitLines,c as stripBom};
|
|
11
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/services/hashline/index.ts"],"sourcesContent":["import type {\n AppliedHashlineEdits,\n FileHeader,\n HashlineRangeInput,\n LineAnchor,\n ParsedTaggedLine,\n PreparedHashlineEdit,\n TaggedLineMarker,\n TaggedLinePrefix,\n} from '../../types/hashline';\n\nconst FNV_OFFSET_BASIS = 0xcbf29ce484222325n;\nconst FNV_PRIME = 0x100000001b3n;\nconst ANCHOR_SPACE = 26n * 26n * 26n;\nconst ASCII_A = 97;\nconst FILE_TAG_PATTERN = /^[A-Za-z0-9_-]{8}$/u;\nconst FILE_HEADER_PATTERN = /^@file (.+)#([A-Za-z0-9_-]{8})$/u;\nconst TAGGED_LINE_PATTERN = /^(>> | {3})?(\\d+)#[a-z]{3}\\|(.*)$/u;\nconst ANCHOR_PATTERN = /^\\s*[>+-]*\\s*(\\d+)\\s*[:#]\\s*([a-zA-Z]{3})(?:\\s*\\|.*)?\\s*$/u;\nconst ASCII_WHITESPACE = /[ \\t\\n\\r\\v\\f]/gu;\n\n/**\n * Return Phi's three-letter whitespace-insensitive FNV-1a64 line anchor.\n * Adapted from pulseaiclub/phi writetool under the MIT license.\n */\nexport function hashLine(line: string): string {\n const bytes = new TextEncoder().encode(line.replace(ASCII_WHITESPACE, ''));\n let hash = FNV_OFFSET_BASIS;\n for (const byte of bytes) {\n hash ^= BigInt(byte);\n hash = BigInt.asUintN(64, hash * FNV_PRIME);\n }\n\n let value = hash % ANCHOR_SPACE;\n const letters = Array.from({ length: 3 }, () => '');\n for (let index = letters.length - 1; index >= 0; index -= 1) {\n letters[index] = String.fromCharCode(ASCII_A + Number(value % 26n));\n value /= 26n;\n }\n return letters.join('');\n}\n\nexport function normalizeToLf(text: string): string {\n return text.replace(/\\r\\n/gu, '\\n').replace(/\\r/gu, '\\n');\n}\n\nexport function stripBom(text: string): string {\n return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n}\n\nexport function splitLines(text: string): string[] {\n return normalizeToLf(stripBom(text)).split('\\n');\n}\n\nexport function normalizeFileTag(value: string): string {\n const trimmed = value.trim();\n const hashIndex = trimmed.lastIndexOf('#');\n const tag = hashIndex === -1 ? trimmed : trimmed.slice(hashIndex + 1);\n if (!FILE_TAG_PATTERN.test(tag)) {\n throw new Error(`Invalid file hash: ${value}. Expected the eight-character tag from @file path#HASH.`);\n }\n return tag;\n}\n\nexport function formatFileHeader(path: string, tag: string): string {\n if (path.length === 0 || path.includes('\\n') || path.includes('\\r')) {\n throw new Error('Invalid file header path. Expected one non-empty path without line breaks.');\n }\n return `@file ${path}#${normalizeFileTag(tag)}`;\n}\n\nexport function parseFileHeader(value: string): FileHeader | undefined {\n const match = FILE_HEADER_PATTERN.exec(value);\n const path = match?.[1];\n const tag = match?.[2];\n return path === undefined || tag === undefined ? undefined : { path, tag };\n}\n\nexport function formatTaggedLine(\n line: string,\n lineNumber: number,\n prefix: TaggedLinePrefix = '',\n anchorSource = line,\n): string {\n assertLineNumber(lineNumber);\n return `${prefix}${lineNumber}#${hashLine(anchorSource)}|${line}`;\n}\n\nexport function formatTaggedLines(lines: readonly string[], firstLine = 1): string {\n return lines.map((line, index) => formatTaggedLine(line, firstLine + index)).join('\\n');\n}\n\nexport function parseTaggedLine(value: string): ParsedTaggedLine | undefined {\n const match = TAGGED_LINE_PATTERN.exec(value);\n const lineText = match?.[2];\n const content = match?.[3];\n if (lineText === undefined || content === undefined) return undefined;\n\n const line = Number.parseInt(lineText, 10);\n if (!Number.isSafeInteger(line) || line < 1) return undefined;\n\n const marker = taggedLineMarker(match?.[1]);\n return marker === undefined ? { content, line } : { content, line, marker };\n}\n\nexport function parseLineAnchor(value: string): LineAnchor {\n if (value.includes('\\n') || value.includes('\\r')) {\n throw new Error(`Invalid line anchor: ${value}. Expected one anchor such as 5#abc, not a pasted multiline block.`);\n }\n\n const match = ANCHOR_PATTERN.exec(value);\n if (!match) {\n throw new Error(\n `Invalid line anchor: ${value}. Expected one anchor such as 5#abc from the latest read or grep result.`,\n );\n }\n\n const line = Number.parseInt(match[1] ?? '', 10);\n const hash = match[2]?.toLowerCase();\n if (!Number.isSafeInteger(line) || line < 1 || hash === undefined) {\n throw new Error(`Invalid line anchor: ${value}. Expected a positive line number and three letters, such as 5#abc.`);\n }\n return { line, hash };\n}\n\nexport function applyHashlineEdits(\n originalContent: string,\n requestedEdits: readonly HashlineRangeInput[],\n): AppliedHashlineEdits {\n const lines = splitLines(originalContent);\n const validated = requestedEdits.map((edit) => validateEdit(edit, lines));\n const edits = deduplicateEdits(validated).sort(compareEdits);\n validateNoOverlaps(edits);\n\n const result = [...lines];\n for (const edit of [...edits].reverse()) {\n const deleteCount = edit.to.line - edit.from.line + 1;\n const replacements = edit.content === null || edit.content === '' ? [] : splitReplacement(edit.content);\n result.splice(edit.from.line - 1, deleteCount, ...replacements);\n }\n return { content: result.join('\\n'), edits };\n}\n\nfunction taggedLineMarker(prefix: string | undefined): TaggedLineMarker | undefined {\n if (prefix === '>> ') return 'match';\n if (prefix === ' ') return 'context';\n return undefined;\n}\n\nfunction assertLineNumber(line: number): void {\n if (!Number.isSafeInteger(line) || line < 1) {\n throw new Error(`Invalid tagged line number: ${String(line)}. Expected a positive safe integer.`);\n }\n}\n\nfunction validateEdit(edit: HashlineRangeInput, lines: readonly string[]): PreparedHashlineEdit {\n const from = parseLineAnchor(edit.from);\n const to = parseLineAnchor(edit.to);\n if (from.line > to.line) {\n throw new Error(`Invalid edit range ${edit.from} to ${edit.to}: the starting line follows the ending line.`);\n }\n if (to.line > lines.length) {\n throw new Error(`Invalid edit range ${edit.from} to ${edit.to}: the file has ${lines.length} lines.`);\n }\n\n validateAnchor(from, lines);\n validateAnchor(to, lines);\n return { from, to, content: edit.content ?? null, source: edit };\n}\n\nfunction validateAnchor(anchor: LineAnchor, lines: readonly string[]): void {\n const line = lines[anchor.line - 1];\n if (line === undefined) throw new Error(`Line ${anchor.line} is outside the current file.`);\n const currentHash = hashLine(line);\n if (currentHash !== anchor.hash) {\n throw new Error(\n `Stale line anchor ${anchor.line}#${anchor.hash}. Current anchor is ${anchor.line}#${currentHash}. Re-read the file and retry.`,\n );\n }\n}\n\nfunction deduplicateEdits(edits: readonly PreparedHashlineEdit[]): PreparedHashlineEdit[] {\n const unique = new Map<string, PreparedHashlineEdit>();\n for (const edit of edits) {\n const key = JSON.stringify([edit.from.line, edit.from.hash, edit.to.line, edit.to.hash, edit.content]);\n if (!unique.has(key)) unique.set(key, edit);\n }\n return [...unique.values()];\n}\n\nfunction compareEdits(left: PreparedHashlineEdit, right: PreparedHashlineEdit): number {\n return left.from.line - right.from.line || left.to.line - right.to.line;\n}\n\nfunction validateNoOverlaps(edits: readonly PreparedHashlineEdit[]): void {\n for (let index = 1; index < edits.length; index += 1) {\n const previous = edits[index - 1];\n const current = edits[index];\n if (previous !== undefined && current !== undefined && current.from.line <= previous.to.line) {\n throw new Error(\n `Overlapping edit ranges ${previous.from.line}-${previous.to.line} and ${current.from.line}-${current.to.line}. Merge them and retry.`,\n );\n }\n }\n}\n\nfunction splitReplacement(content: string): string[] {\n const normalized = normalizeToLf(content);\n const trimmed = normalized.endsWith('\\n') ? normalized.slice(0, -1) : normalized;\n return trimmed === '' ? [] : trimmed.split('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
//#region src/types/hashline.d.ts
|
|
2
|
-
export interface HashlineRangeInput {
|
|
3
|
-
readonly from: string;
|
|
4
|
-
readonly to: string;
|
|
5
|
-
readonly content?: string | null;
|
|
6
|
-
}
|
|
7
|
-
export interface LineAnchor {
|
|
8
|
-
readonly line: number;
|
|
9
|
-
readonly hash: string;
|
|
10
|
-
}
|
|
11
|
-
export interface PreparedHashlineEdit {
|
|
12
|
-
readonly from: LineAnchor;
|
|
13
|
-
readonly to: LineAnchor;
|
|
14
|
-
readonly content: string | null;
|
|
15
|
-
readonly source: HashlineRangeInput;
|
|
16
|
-
}
|
|
17
|
-
export interface AppliedHashlineEdits {
|
|
18
|
-
readonly content: string;
|
|
19
|
-
readonly edits: readonly PreparedHashlineEdit[];
|
|
20
|
-
}
|
|
21
|
-
export interface FileHeader {
|
|
22
|
-
readonly path: string;
|
|
23
|
-
readonly tag: string;
|
|
24
|
-
}
|
|
25
|
-
export type TaggedLineMarker = 'match' | 'context';
|
|
26
|
-
export interface ParsedTaggedLine {
|
|
27
|
-
readonly content: string;
|
|
28
|
-
readonly line: number;
|
|
29
|
-
readonly marker?: TaggedLineMarker;
|
|
30
|
-
}
|
|
31
|
-
export type TaggedLinePrefix = '' | '>> ' | ' ';
|
|
32
|
-
//#endregion
|
|
33
|
-
//# sourceMappingURL=hashline.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hashline.d.cts","names":[],"sources":["../../src/types/hashline.ts"],"mappings":";iBAAiB;WACN;WACA;WACA;;iBAGM;WACN;WACA;;iBAGM;WACN,MAAM;WACN,IAAI;WACJ;WACA,QAAQ;;iBAGF;WACN;WACA,gBAAgB;;iBAGV;WACN;WACA;;YAGC;iBAEK;WACN;WACA;WACA,SAAS;;YAGR"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
//#region src/types/hashline.d.ts
|
|
2
|
-
export interface HashlineRangeInput {
|
|
3
|
-
readonly from: string;
|
|
4
|
-
readonly to: string;
|
|
5
|
-
readonly content?: string | null;
|
|
6
|
-
}
|
|
7
|
-
export interface LineAnchor {
|
|
8
|
-
readonly line: number;
|
|
9
|
-
readonly hash: string;
|
|
10
|
-
}
|
|
11
|
-
export interface PreparedHashlineEdit {
|
|
12
|
-
readonly from: LineAnchor;
|
|
13
|
-
readonly to: LineAnchor;
|
|
14
|
-
readonly content: string | null;
|
|
15
|
-
readonly source: HashlineRangeInput;
|
|
16
|
-
}
|
|
17
|
-
export interface AppliedHashlineEdits {
|
|
18
|
-
readonly content: string;
|
|
19
|
-
readonly edits: readonly PreparedHashlineEdit[];
|
|
20
|
-
}
|
|
21
|
-
export interface FileHeader {
|
|
22
|
-
readonly path: string;
|
|
23
|
-
readonly tag: string;
|
|
24
|
-
}
|
|
25
|
-
export type TaggedLineMarker = 'match' | 'context';
|
|
26
|
-
export interface ParsedTaggedLine {
|
|
27
|
-
readonly content: string;
|
|
28
|
-
readonly line: number;
|
|
29
|
-
readonly marker?: TaggedLineMarker;
|
|
30
|
-
}
|
|
31
|
-
export type TaggedLinePrefix = '' | '>> ' | ' ';
|
|
32
|
-
//#endregion
|
|
33
|
-
//# sourceMappingURL=hashline.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hashline.d.mts","names":[],"sources":["../../src/types/hashline.ts"],"mappings":";iBAAiB;WACN;WACA;WACA;;iBAGM;WACN;WACA;;iBAGM;WACN,MAAM;WACN,IAAI;WACJ;WACA,QAAQ;;iBAGF;WACN;WACA,gBAAgB;;iBAGV;WACN;WACA;;YAGC;iBAEK;WACN;WACA;WACA,SAAS;;YAGR"}
|