@shrkcrft/compress 0.1.0-alpha.16
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/LICENSE +21 -0
- package/README.md +21 -0
- package/dist/cache/align-volatile-tokens.d.ts +13 -0
- package/dist/cache/align-volatile-tokens.d.ts.map +1 -0
- package/dist/cache/align-volatile-tokens.js +51 -0
- package/dist/cache/alignment-map.d.ts +23 -0
- package/dist/cache/alignment-map.d.ts.map +1 -0
- package/dist/cache/alignment-map.js +1 -0
- package/dist/cache/alignment-result.d.ts +11 -0
- package/dist/cache/alignment-result.d.ts.map +1 -0
- package/dist/cache/alignment-result.js +1 -0
- package/dist/cache/detect-volatile-tokens.d.ts +10 -0
- package/dist/cache/detect-volatile-tokens.d.ts.map +1 -0
- package/dist/cache/detect-volatile-tokens.js +41 -0
- package/dist/cache/placeholder.d.ts +28 -0
- package/dist/cache/placeholder.d.ts.map +1 -0
- package/dist/cache/placeholder.js +0 -0
- package/dist/cache/restore-volatile-tokens.d.ts +10 -0
- package/dist/cache/restore-volatile-tokens.d.ts.map +1 -0
- package/dist/cache/restore-volatile-tokens.js +21 -0
- package/dist/cache/volatile-classify.d.ts +11 -0
- package/dist/cache/volatile-classify.d.ts.map +1 -0
- package/dist/cache/volatile-classify.js +35 -0
- package/dist/cache/volatile-kind.d.ts +13 -0
- package/dist/cache/volatile-kind.d.ts.map +1 -0
- package/dist/cache/volatile-kind.js +13 -0
- package/dist/cache/volatile-token.d.ts +14 -0
- package/dist/cache/volatile-token.d.ts.map +1 -0
- package/dist/cache/volatile-token.js +1 -0
- package/dist/ccr/ccr-entry.d.ts +13 -0
- package/dist/ccr/ccr-entry.d.ts.map +1 -0
- package/dist/ccr/ccr-entry.js +1 -0
- package/dist/ccr/ccr-key.d.ts +9 -0
- package/dist/ccr/ccr-key.d.ts.map +1 -0
- package/dist/ccr/ccr-key.js +19 -0
- package/dist/ccr/ccr-marker.d.ts +23 -0
- package/dist/ccr/ccr-marker.d.ts.map +1 -0
- package/dist/ccr/ccr-marker.js +30 -0
- package/dist/ccr/ccr-store.d.ts +18 -0
- package/dist/ccr/ccr-store.d.ts.map +1 -0
- package/dist/ccr/ccr-store.js +1 -0
- package/dist/ccr/file-ccr-store.d.ts +19 -0
- package/dist/ccr/file-ccr-store.d.ts.map +1 -0
- package/dist/ccr/file-ccr-store.js +53 -0
- package/dist/ccr/in-memory-ccr-store.d.ts +21 -0
- package/dist/ccr/in-memory-ccr-store.d.ts.map +1 -0
- package/dist/ccr/in-memory-ccr-store.js +45 -0
- package/dist/ccr/ttl-file-ccr-store.d.ts +43 -0
- package/dist/ccr/ttl-file-ccr-store.d.ts.map +1 -0
- package/dist/ccr/ttl-file-ccr-store.js +117 -0
- package/dist/code/compress-code.d.ts +4 -0
- package/dist/code/compress-code.d.ts.map +1 -0
- package/dist/code/compress-code.js +294 -0
- package/dist/compress-content.d.ts +11 -0
- package/dist/compress-content.d.ts.map +1 -0
- package/dist/compress-content.js +79 -0
- package/dist/content/content-type.d.ts +28 -0
- package/dist/content/content-type.d.ts.map +1 -0
- package/dist/content/content-type.js +28 -0
- package/dist/content/detect-content-type.d.ts +9 -0
- package/dist/content/detect-content-type.d.ts.map +1 -0
- package/dist/content/detect-content-type.js +184 -0
- package/dist/content/segment.d.ts +21 -0
- package/dist/content/segment.d.ts.map +1 -0
- package/dist/content/segment.js +117 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/json/compress-json.d.ts +18 -0
- package/dist/json/compress-json.d.ts.map +1 -0
- package/dist/json/compress-json.js +139 -0
- package/dist/json/render-compact-json.d.ts +10 -0
- package/dist/json/render-compact-json.d.ts.map +1 -0
- package/dist/json/render-compact-json.js +18 -0
- package/dist/relevance/bm25.d.ts +26 -0
- package/dist/relevance/bm25.d.ts.map +1 -0
- package/dist/relevance/bm25.js +115 -0
- package/dist/result/compress-options.d.ts +26 -0
- package/dist/result/compress-options.d.ts.map +1 -0
- package/dist/result/compress-options.js +1 -0
- package/dist/result/compression-result.d.ts +26 -0
- package/dist/result/compression-result.d.ts.map +1 -0
- package/dist/result/compression-result.js +1 -0
- package/dist/result/compression-strategy.d.ts +30 -0
- package/dist/result/compression-strategy.d.ts.map +1 -0
- package/dist/result/compression-strategy.js +30 -0
- package/dist/table/adaptive-size.d.ts +46 -0
- package/dist/table/adaptive-size.d.ts.map +1 -0
- package/dist/table/adaptive-size.js +170 -0
- package/dist/table/apply-value-dictionaries.d.ts +30 -0
- package/dist/table/apply-value-dictionaries.d.ts.map +1 -0
- package/dist/table/apply-value-dictionaries.js +99 -0
- package/dist/table/column-presence.d.ts +20 -0
- package/dist/table/column-presence.d.ts.map +1 -0
- package/dist/table/column-presence.js +52 -0
- package/dist/table/columnar-json.d.ts +24 -0
- package/dist/table/columnar-json.d.ts.map +1 -0
- package/dist/table/columnar-json.js +83 -0
- package/dist/table/columnar-table.d.ts +24 -0
- package/dist/table/columnar-table.d.ts.map +1 -0
- package/dist/table/columnar-table.js +1 -0
- package/dist/table/compact-object-array.d.ts +12 -0
- package/dist/table/compact-object-array.d.ts.map +1 -0
- package/dist/table/compact-object-array.js +88 -0
- package/dist/table/field-spec.d.ts +13 -0
- package/dist/table/field-spec.d.ts.map +1 -0
- package/dist/table/field-spec.js +1 -0
- package/dist/table/object-map.d.ts +28 -0
- package/dist/table/object-map.d.ts.map +1 -0
- package/dist/table/object-map.js +119 -0
- package/dist/table/render-table.d.ts +11 -0
- package/dist/table/render-table.d.ts.map +1 -0
- package/dist/table/render-table.js +39 -0
- package/dist/table/sample-object-array.d.ts +11 -0
- package/dist/table/sample-object-array.d.ts.map +1 -0
- package/dist/table/sample-object-array.js +171 -0
- package/dist/table/sample-options.d.ts +29 -0
- package/dist/table/sample-options.d.ts.map +1 -0
- package/dist/table/sample-options.js +1 -0
- package/dist/table/sampled-table.d.ts +33 -0
- package/dist/table/sampled-table.d.ts.map +1 -0
- package/dist/table/sampled-table.js +8 -0
- package/dist/table/table-compaction.d.ts +19 -0
- package/dist/table/table-compaction.d.ts.map +1 -0
- package/dist/table/table-compaction.js +1 -0
- package/dist/table/table-formats.d.ts +23 -0
- package/dist/table/table-formats.d.ts.map +1 -0
- package/dist/table/table-formats.js +233 -0
- package/dist/text/compress-diff.d.ts +20 -0
- package/dist/text/compress-diff.d.ts.map +1 -0
- package/dist/text/compress-diff.js +344 -0
- package/dist/text/compress-lines.d.ts +12 -0
- package/dist/text/compress-lines.d.ts.map +1 -0
- package/dist/text/compress-lines.js +44 -0
- package/dist/text/compress-log.d.ts +12 -0
- package/dist/text/compress-log.d.ts.map +1 -0
- package/dist/text/compress-log.js +202 -0
- package/dist/text/compress-markdown.d.ts +15 -0
- package/dist/text/compress-markdown.d.ts.map +1 -0
- package/dist/text/compress-markdown.js +96 -0
- package/dist/text/compress-search.d.ts +11 -0
- package/dist/text/compress-search.d.ts.map +1 -0
- package/dist/text/compress-search.js +78 -0
- package/dist/text/finalize.d.ts +21 -0
- package/dist/text/finalize.d.ts.map +1 -0
- package/dist/text/finalize.js +54 -0
- package/dist/text/line-utils.d.ts +20 -0
- package/dist/text/line-utils.d.ts.map +1 -0
- package/dist/text/line-utils.js +65 -0
- package/dist/text/lockfile-names.d.ts +3 -0
- package/dist/text/lockfile-names.d.ts.map +1 -0
- package/dist/text/lockfile-names.js +33 -0
- package/dist/text/log-template.d.ts +31 -0
- package/dist/text/log-template.d.ts.map +1 -0
- package/dist/text/log-template.js +239 -0
- package/dist/tokens/estimate-tokens.d.ts +17 -0
- package/dist/tokens/estimate-tokens.d.ts.map +1 -0
- package/dist/tokens/estimate-tokens.js +53 -0
- package/dist/tokens/token-savings.d.ts +20 -0
- package/dist/tokens/token-savings.d.ts.map +1 -0
- package/dist/tokens/token-savings.js +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ICcrStore } from './ccr-store.js';
|
|
2
|
+
import type { ICcrEntry } from './ccr-entry.js';
|
|
3
|
+
/**
|
|
4
|
+
* In-memory CCR backend. Used by the MCP server, whose process is long-lived,
|
|
5
|
+
* so a `compress_context` call and a later `retrieve_original` call in the
|
|
6
|
+
* same session share one store. Holding originals in memory (never on disk)
|
|
7
|
+
* keeps the MCP-never-writes contract intact.
|
|
8
|
+
*
|
|
9
|
+
* Bounded by an insertion-order capacity: when full, the oldest entry is
|
|
10
|
+
* evicted (a retrieval miss just means the agent re-runs the producing call).
|
|
11
|
+
*/
|
|
12
|
+
export declare class InMemoryCcrStore implements ICcrStore {
|
|
13
|
+
private readonly entries;
|
|
14
|
+
private readonly capacity;
|
|
15
|
+
constructor(capacity?: number);
|
|
16
|
+
put(content: string): string;
|
|
17
|
+
get(key: string): ICcrEntry | undefined;
|
|
18
|
+
has(key: string): boolean;
|
|
19
|
+
size(): number;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=in-memory-ccr-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-ccr-store.d.ts","sourceRoot":"","sources":["../../src/ccr/in-memory-ccr-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD;;;;;;;;GAQG;AACH,qBAAa,gBAAiB,YAAW,SAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,QAAQ,SAAM;IAK1B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAiB5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIvC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,IAAI,IAAI,MAAM;CAGf"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { ccrKey } from "./ccr-key.js";
|
|
3
|
+
/**
|
|
4
|
+
* In-memory CCR backend. Used by the MCP server, whose process is long-lived,
|
|
5
|
+
* so a `compress_context` call and a later `retrieve_original` call in the
|
|
6
|
+
* same session share one store. Holding originals in memory (never on disk)
|
|
7
|
+
* keeps the MCP-never-writes contract intact.
|
|
8
|
+
*
|
|
9
|
+
* Bounded by an insertion-order capacity: when full, the oldest entry is
|
|
10
|
+
* evicted (a retrieval miss just means the agent re-runs the producing call).
|
|
11
|
+
*/
|
|
12
|
+
export class InMemoryCcrStore {
|
|
13
|
+
entries = new Map();
|
|
14
|
+
capacity;
|
|
15
|
+
constructor(capacity = 512) {
|
|
16
|
+
// No logic beyond field init — capacity is a plain bound.
|
|
17
|
+
this.capacity = capacity > 0 ? capacity : 512;
|
|
18
|
+
}
|
|
19
|
+
put(content) {
|
|
20
|
+
const key = ccrKey(content);
|
|
21
|
+
if (this.entries.has(key)) {
|
|
22
|
+
// Refresh recency: re-insert so it isn't the next eviction victim.
|
|
23
|
+
const existing = this.entries.get(key);
|
|
24
|
+
this.entries.delete(key);
|
|
25
|
+
this.entries.set(key, existing);
|
|
26
|
+
return key;
|
|
27
|
+
}
|
|
28
|
+
if (this.entries.size >= this.capacity) {
|
|
29
|
+
const oldest = this.entries.keys().next().value;
|
|
30
|
+
if (oldest !== undefined)
|
|
31
|
+
this.entries.delete(oldest);
|
|
32
|
+
}
|
|
33
|
+
this.entries.set(key, { key, content, bytes: Buffer.byteLength(content, 'utf8') });
|
|
34
|
+
return key;
|
|
35
|
+
}
|
|
36
|
+
get(key) {
|
|
37
|
+
return this.entries.get(key);
|
|
38
|
+
}
|
|
39
|
+
has(key) {
|
|
40
|
+
return this.entries.has(key);
|
|
41
|
+
}
|
|
42
|
+
size() {
|
|
43
|
+
return this.entries.size;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ICcrStore } from './ccr-store.js';
|
|
2
|
+
import type { ICcrEntry } from './ccr-entry.js';
|
|
3
|
+
export interface ITtlFileCcrStoreOptions {
|
|
4
|
+
/** Entry lifetime in ms. 0 (default) = no expiry. */
|
|
5
|
+
ttlMs?: number;
|
|
6
|
+
/** Max live entries; oldest are evicted past this. 0 (default) = unbounded. */
|
|
7
|
+
maxEntries?: number;
|
|
8
|
+
/** Refresh an entry's timestamp on read (sliding TTL + LRU). Default false. */
|
|
9
|
+
refreshOnAccess?: boolean;
|
|
10
|
+
/** Injectable clock for deterministic tests. Defaults to `Date.now`. */
|
|
11
|
+
now?: () => number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Filesystem-backed CCR store with TTL + size eviction, for the CLI write path
|
|
15
|
+
* (P5.1). Like {@link FileCcrStore} each original is a content-addressed file
|
|
16
|
+
* (cross-process by construction), but the file's mtime is the entry timestamp:
|
|
17
|
+
* entries older than `ttlMs` are treated as absent (and lazily removed), and a
|
|
18
|
+
* `put` past `maxEntries` evicts the oldest. The MCP server never uses this —
|
|
19
|
+
* it stays in-memory to honour the read-only contract.
|
|
20
|
+
*
|
|
21
|
+
* Stateful by design (a cache, not the deterministic engine path); the clock is
|
|
22
|
+
* injectable so tests are reproducible.
|
|
23
|
+
*/
|
|
24
|
+
export declare class TtlFileCcrStore implements ICcrStore {
|
|
25
|
+
private readonly dir;
|
|
26
|
+
private readonly ttlMs;
|
|
27
|
+
private readonly maxEntries;
|
|
28
|
+
private readonly refreshOnAccess;
|
|
29
|
+
private readonly now;
|
|
30
|
+
constructor(dir: string, opts?: ITtlFileCcrStoreOptions);
|
|
31
|
+
private pathFor;
|
|
32
|
+
private stamp;
|
|
33
|
+
private isExpired;
|
|
34
|
+
private remove;
|
|
35
|
+
put(content: string): string;
|
|
36
|
+
get(key: string): ICcrEntry | undefined;
|
|
37
|
+
has(key: string): boolean;
|
|
38
|
+
size(): number;
|
|
39
|
+
/** Live (non-expired) entries, sweeping expired files as a side effect. */
|
|
40
|
+
private liveEntries;
|
|
41
|
+
private evict;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=ttl-file-ccr-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ttl-file-ccr-store.d.ts","sourceRoot":"","sources":["../../src/ccr/ttl-file-ccr-store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMhD,MAAM,WAAW,uBAAuB;IACtC,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEvB,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,uBAA4B;IAS3D,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,MAAM;IAQd,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAU5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAavC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAWzB,IAAI,IAAI,MAAM;IAId,2EAA2E;IAC3E,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,KAAK;CAOd"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, statSync, utimesSync, rmSync, } from 'node:fs';
|
|
2
|
+
import * as nodePath from 'node:path';
|
|
3
|
+
import { Buffer } from 'node:buffer';
|
|
4
|
+
import { ccrKey } from "./ccr-key.js";
|
|
5
|
+
/** CCR keys are content hashes — hex only. Rejects path-traversal lookups. */
|
|
6
|
+
const VALID_KEY = /^[0-9a-f]{1,64}$/;
|
|
7
|
+
/**
|
|
8
|
+
* Filesystem-backed CCR store with TTL + size eviction, for the CLI write path
|
|
9
|
+
* (P5.1). Like {@link FileCcrStore} each original is a content-addressed file
|
|
10
|
+
* (cross-process by construction), but the file's mtime is the entry timestamp:
|
|
11
|
+
* entries older than `ttlMs` are treated as absent (and lazily removed), and a
|
|
12
|
+
* `put` past `maxEntries` evicts the oldest. The MCP server never uses this —
|
|
13
|
+
* it stays in-memory to honour the read-only contract.
|
|
14
|
+
*
|
|
15
|
+
* Stateful by design (a cache, not the deterministic engine path); the clock is
|
|
16
|
+
* injectable so tests are reproducible.
|
|
17
|
+
*/
|
|
18
|
+
export class TtlFileCcrStore {
|
|
19
|
+
dir;
|
|
20
|
+
ttlMs;
|
|
21
|
+
maxEntries;
|
|
22
|
+
refreshOnAccess;
|
|
23
|
+
now;
|
|
24
|
+
constructor(dir, opts = {}) {
|
|
25
|
+
// Field init only.
|
|
26
|
+
this.dir = dir;
|
|
27
|
+
this.ttlMs = opts.ttlMs && opts.ttlMs > 0 ? opts.ttlMs : 0;
|
|
28
|
+
this.maxEntries = opts.maxEntries && opts.maxEntries > 0 ? opts.maxEntries : 0;
|
|
29
|
+
this.refreshOnAccess = opts.refreshOnAccess ?? false;
|
|
30
|
+
this.now = opts.now ?? (() => Date.now());
|
|
31
|
+
}
|
|
32
|
+
pathFor(key) {
|
|
33
|
+
return nodePath.join(this.dir, `${key}.txt`);
|
|
34
|
+
}
|
|
35
|
+
stamp(file, ms) {
|
|
36
|
+
const d = new Date(ms);
|
|
37
|
+
utimesSync(file, d, d);
|
|
38
|
+
}
|
|
39
|
+
isExpired(mtimeMs) {
|
|
40
|
+
return this.ttlMs > 0 && this.now() - mtimeMs > this.ttlMs;
|
|
41
|
+
}
|
|
42
|
+
remove(file) {
|
|
43
|
+
try {
|
|
44
|
+
rmSync(file, { force: true });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// best-effort eviction
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
put(content) {
|
|
51
|
+
const key = ccrKey(content);
|
|
52
|
+
const file = this.pathFor(key);
|
|
53
|
+
mkdirSync(this.dir, { recursive: true });
|
|
54
|
+
writeFileSync(file, content, 'utf8');
|
|
55
|
+
this.stamp(file, this.now());
|
|
56
|
+
this.evict();
|
|
57
|
+
return key;
|
|
58
|
+
}
|
|
59
|
+
get(key) {
|
|
60
|
+
if (!VALID_KEY.test(key))
|
|
61
|
+
return undefined;
|
|
62
|
+
const file = this.pathFor(key);
|
|
63
|
+
if (!existsSync(file))
|
|
64
|
+
return undefined;
|
|
65
|
+
if (this.isExpired(statSync(file).mtimeMs)) {
|
|
66
|
+
this.remove(file);
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
if (this.refreshOnAccess)
|
|
70
|
+
this.stamp(file, this.now());
|
|
71
|
+
const content = readFileSync(file, 'utf8');
|
|
72
|
+
return { key, content, bytes: Buffer.byteLength(content, 'utf8') };
|
|
73
|
+
}
|
|
74
|
+
has(key) {
|
|
75
|
+
if (!VALID_KEY.test(key))
|
|
76
|
+
return false;
|
|
77
|
+
const file = this.pathFor(key);
|
|
78
|
+
if (!existsSync(file))
|
|
79
|
+
return false;
|
|
80
|
+
if (this.isExpired(statSync(file).mtimeMs)) {
|
|
81
|
+
this.remove(file);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
size() {
|
|
87
|
+
return this.liveEntries().length;
|
|
88
|
+
}
|
|
89
|
+
/** Live (non-expired) entries, sweeping expired files as a side effect. */
|
|
90
|
+
liveEntries() {
|
|
91
|
+
if (!existsSync(this.dir))
|
|
92
|
+
return [];
|
|
93
|
+
const out = [];
|
|
94
|
+
for (const name of readdirSync(this.dir)) {
|
|
95
|
+
if (!name.endsWith('.txt'))
|
|
96
|
+
continue;
|
|
97
|
+
const file = nodePath.join(this.dir, name);
|
|
98
|
+
const mtimeMs = statSync(file).mtimeMs;
|
|
99
|
+
if (this.isExpired(mtimeMs)) {
|
|
100
|
+
this.remove(file);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
out.push({ file, mtimeMs });
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
evict() {
|
|
108
|
+
if (this.maxEntries <= 0)
|
|
109
|
+
return;
|
|
110
|
+
const live = this.liveEntries();
|
|
111
|
+
if (live.length <= this.maxEntries)
|
|
112
|
+
return;
|
|
113
|
+
live.sort((a, b) => a.mtimeMs - b.mtimeMs); // oldest first
|
|
114
|
+
for (const e of live.slice(0, live.length - this.maxEntries))
|
|
115
|
+
this.remove(e.file);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ICompressionResult } from '../result/compression-result.js';
|
|
2
|
+
import type { ICompressOptions } from '../result/compress-options.js';
|
|
3
|
+
export declare function compressCode(text: string, opts?: ICompressOptions): ICompressionResult;
|
|
4
|
+
//# sourceMappingURL=compress-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compress-code.d.ts","sourceRoot":"","sources":["../../src/code/compress-code.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAyQtE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,kBAAkB,CA0C1F"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { EContentType } from "../content/content-type.js";
|
|
2
|
+
import { ECompressionStrategy } from "../result/compression-strategy.js";
|
|
3
|
+
import { splitLines, elide, queryTokens, queryOverlap } from "../text/line-utils.js";
|
|
4
|
+
import { finalizeLossy, passthroughResult } from "../text/finalize.js";
|
|
5
|
+
const DECL_OPEN = /^(?:export\s+)?(?:default\s+)?(?:declare\s+)?(?:abstract\s+)?(?:class|interface|enum|namespace|module)\b/;
|
|
6
|
+
const PURE_CLOSE = /^[)}\]]+[;,]?$/;
|
|
7
|
+
const REGEX_KEYWORDS = new Set([
|
|
8
|
+
'return', 'typeof', 'instanceof', 'in', 'of', 'new', 'delete', 'void', 'do', 'else', 'yield', 'await', 'case', 'throw',
|
|
9
|
+
]);
|
|
10
|
+
// Block-opening keywords whose body has no preceding `)` (so `closeParen` won't be set).
|
|
11
|
+
const CONTROL_BODY_WORDS = new Set(['do', 'else', 'try', 'finally']);
|
|
12
|
+
function isIdentChar(c) {
|
|
13
|
+
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_' || c === '$';
|
|
14
|
+
}
|
|
15
|
+
/** Advance past a string literal; returns the index after the closing quote (or EOL). */
|
|
16
|
+
function skipString(line, start, quote) {
|
|
17
|
+
let i = start + 1;
|
|
18
|
+
while (i < line.length) {
|
|
19
|
+
const c = line[i];
|
|
20
|
+
if (c === '\\') {
|
|
21
|
+
i += 2;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (c === quote)
|
|
25
|
+
return i + 1;
|
|
26
|
+
i += 1;
|
|
27
|
+
}
|
|
28
|
+
return line.length;
|
|
29
|
+
}
|
|
30
|
+
/** Index after a regex literal, or -1 if it doesn't close on this line (then it
|
|
31
|
+
* wasn't a regex — a lone `/` to EOL is division/a path, not a literal). */
|
|
32
|
+
function skipRegex(line, start) {
|
|
33
|
+
let i = start + 1;
|
|
34
|
+
let inClass = false;
|
|
35
|
+
while (i < line.length) {
|
|
36
|
+
const c = line[i];
|
|
37
|
+
if (c === '\\') {
|
|
38
|
+
i += 2;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (inClass) {
|
|
42
|
+
if (c === ']')
|
|
43
|
+
inClass = false;
|
|
44
|
+
i += 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (c === '[')
|
|
48
|
+
inClass = true;
|
|
49
|
+
else if (c === '/')
|
|
50
|
+
return i + 1;
|
|
51
|
+
i += 1;
|
|
52
|
+
}
|
|
53
|
+
return -1;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Scan one line, updating the block-comment/template state AND pushing/popping
|
|
57
|
+
* the block-kind stack per brace. Each `{` is classified at the moment it is
|
|
58
|
+
* opened, using the enclosing kind plus the line-local token context.
|
|
59
|
+
*/
|
|
60
|
+
function applyLineToStack(line, state, stack) {
|
|
61
|
+
let i = 0;
|
|
62
|
+
let prevWord = '';
|
|
63
|
+
let prevValue = false; // previous token can end an expression (ident/value/`)`/`]`/string/regex)
|
|
64
|
+
let arrow = false; // just saw `=>`
|
|
65
|
+
let closeParen = false; // saw `)` and only type-annotation tokens since
|
|
66
|
+
let typeDepth = 0; // `<…>` / `[…]` nesting within a return-type annotation
|
|
67
|
+
while (i < line.length) {
|
|
68
|
+
if (state.inBlockComment) {
|
|
69
|
+
if (line.startsWith('*/', i)) {
|
|
70
|
+
state.inBlockComment = false;
|
|
71
|
+
i += 2;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
i += 1;
|
|
75
|
+
}
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (state.inTemplate) {
|
|
79
|
+
const c = line[i];
|
|
80
|
+
if (c === '\\') {
|
|
81
|
+
i += 2;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (c === '`') {
|
|
85
|
+
state.inTemplate = false;
|
|
86
|
+
prevValue = true;
|
|
87
|
+
prevWord = '';
|
|
88
|
+
arrow = false;
|
|
89
|
+
}
|
|
90
|
+
i += 1;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const c = line[i];
|
|
94
|
+
if (c === ' ' || c === '\t') {
|
|
95
|
+
i += 1;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (line.startsWith('//', i))
|
|
99
|
+
break;
|
|
100
|
+
if (line.startsWith('/*', i)) {
|
|
101
|
+
state.inBlockComment = true;
|
|
102
|
+
i += 2;
|
|
103
|
+
prevWord = '';
|
|
104
|
+
arrow = false;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (c === '/') {
|
|
108
|
+
const regexCtx = REGEX_KEYWORDS.has(prevWord) || !prevValue;
|
|
109
|
+
const end = regexCtx ? skipRegex(line, i) : -1;
|
|
110
|
+
if (end >= 0) {
|
|
111
|
+
i = end;
|
|
112
|
+
prevValue = true; // a regex literal is a value
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
i += 1;
|
|
116
|
+
prevValue = false; // division operator (or unterminated `/`)
|
|
117
|
+
}
|
|
118
|
+
prevWord = '';
|
|
119
|
+
arrow = false;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (c === "'" || c === '"') {
|
|
123
|
+
i = skipString(line, i, c);
|
|
124
|
+
prevValue = true;
|
|
125
|
+
closeParen = false;
|
|
126
|
+
prevWord = '';
|
|
127
|
+
arrow = false;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (c === '`') {
|
|
131
|
+
state.inTemplate = true;
|
|
132
|
+
i += 1;
|
|
133
|
+
prevValue = true;
|
|
134
|
+
closeParen = false;
|
|
135
|
+
prevWord = '';
|
|
136
|
+
arrow = false;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (c === '=' && line[i + 1] === '>') {
|
|
140
|
+
arrow = true;
|
|
141
|
+
prevValue = false;
|
|
142
|
+
prevWord = '';
|
|
143
|
+
i += 2;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (c === '{') {
|
|
147
|
+
const top = stack.length > 0 ? stack[stack.length - 1] : 'decl';
|
|
148
|
+
const kind = top === 'func' || arrow || closeParen || CONTROL_BODY_WORDS.has(prevWord) ? 'func' : 'decl';
|
|
149
|
+
stack.push(kind);
|
|
150
|
+
prevValue = false;
|
|
151
|
+
closeParen = false;
|
|
152
|
+
typeDepth = 0;
|
|
153
|
+
arrow = false;
|
|
154
|
+
prevWord = '';
|
|
155
|
+
i += 1;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (c === '}') {
|
|
159
|
+
if (stack.length > 0)
|
|
160
|
+
stack.pop();
|
|
161
|
+
prevValue = false;
|
|
162
|
+
closeParen = false;
|
|
163
|
+
typeDepth = 0;
|
|
164
|
+
arrow = false;
|
|
165
|
+
prevWord = '';
|
|
166
|
+
i += 1;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (c === ')') {
|
|
170
|
+
closeParen = true;
|
|
171
|
+
typeDepth = 0;
|
|
172
|
+
prevValue = true;
|
|
173
|
+
prevWord = '';
|
|
174
|
+
arrow = false;
|
|
175
|
+
i += 1;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (c === '[') {
|
|
179
|
+
// In a return-type window (`): [a, b] {`) a `[` opens a TUPLE type — keep
|
|
180
|
+
// closeParen and deepen; otherwise it's an array/index and ends the window.
|
|
181
|
+
if (closeParen)
|
|
182
|
+
typeDepth += 1;
|
|
183
|
+
else
|
|
184
|
+
closeParen = false;
|
|
185
|
+
prevValue = false;
|
|
186
|
+
prevWord = '';
|
|
187
|
+
arrow = false;
|
|
188
|
+
i += 1;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (c === ']') {
|
|
192
|
+
if (closeParen && typeDepth > 0)
|
|
193
|
+
typeDepth -= 1;
|
|
194
|
+
prevValue = true;
|
|
195
|
+
prevWord = '';
|
|
196
|
+
arrow = false;
|
|
197
|
+
i += 1;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (c === '(' || c === ';' || c === '=') {
|
|
201
|
+
closeParen = false;
|
|
202
|
+
typeDepth = 0;
|
|
203
|
+
prevValue = false;
|
|
204
|
+
prevWord = '';
|
|
205
|
+
arrow = false;
|
|
206
|
+
i += 1;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
// A `,` keeps closeParen ONLY inside a generic/tuple return type
|
|
210
|
+
// (`): Record<string, Item> {` — typeDepth > 0). A top-level comma
|
|
211
|
+
// (`resolve(): void, options: {`) ends the return-type window so the next
|
|
212
|
+
// `{` is correctly an object/interface body, not a function body.
|
|
213
|
+
if (c === ',') {
|
|
214
|
+
if (!(closeParen && typeDepth > 0))
|
|
215
|
+
closeParen = false;
|
|
216
|
+
prevValue = false;
|
|
217
|
+
prevWord = '';
|
|
218
|
+
arrow = false;
|
|
219
|
+
i += 1;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (isIdentChar(c)) {
|
|
223
|
+
let j = i;
|
|
224
|
+
while (j < line.length && isIdentChar(line[j]))
|
|
225
|
+
j += 1;
|
|
226
|
+
prevWord = line.slice(i, j);
|
|
227
|
+
prevValue = true; // identifiers / numbers are values (keyword check is separate)
|
|
228
|
+
arrow = false;
|
|
229
|
+
i = j;
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
// Any other punctuation (`:` `.` `<` `>` `+` `-` …): leave closeParen so a
|
|
233
|
+
// return-type annotation `): Foo<T> {` still reads as a func body. Track
|
|
234
|
+
// `<…>` nesting inside that window so a comma there is a generic separator.
|
|
235
|
+
if (closeParen) {
|
|
236
|
+
// A `<` opens a generic only when it follows a type NAME (prevWord set);
|
|
237
|
+
// a `<` after `)`/`]` (prevWord cleared) is a less-than comparison and
|
|
238
|
+
// must NOT bump typeDepth (else a later `,` wrongly keeps closeParen).
|
|
239
|
+
if (c === '<' && prevWord.length > 0)
|
|
240
|
+
typeDepth += 1;
|
|
241
|
+
else if (c === '>' && typeDepth > 0)
|
|
242
|
+
typeDepth -= 1;
|
|
243
|
+
}
|
|
244
|
+
prevValue = false;
|
|
245
|
+
prevWord = '';
|
|
246
|
+
arrow = false;
|
|
247
|
+
i += 1;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
export function compressCode(text, opts = {}) {
|
|
251
|
+
const lines = splitLines(text);
|
|
252
|
+
const minLines = opts.minLines ?? 15;
|
|
253
|
+
if (lines.length < minLines)
|
|
254
|
+
return passthroughResult(text, EContentType.SourceCode);
|
|
255
|
+
const tokens = queryTokens(opts.query);
|
|
256
|
+
const state = { inBlockComment: false, inTemplate: false };
|
|
257
|
+
const stack = [];
|
|
258
|
+
const keep = new Set();
|
|
259
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
260
|
+
const raw = lines[i] ?? '';
|
|
261
|
+
const trimmed = raw.trim();
|
|
262
|
+
const enclosing = stack.length > 0 ? stack[stack.length - 1] : 'decl';
|
|
263
|
+
const inComment = state.inBlockComment;
|
|
264
|
+
if (trimmed.length === 0) {
|
|
265
|
+
// blanks elided
|
|
266
|
+
}
|
|
267
|
+
else if (inComment) {
|
|
268
|
+
if (enclosing !== 'func')
|
|
269
|
+
keep.add(i); // a top-level/decl block comment
|
|
270
|
+
}
|
|
271
|
+
else if (enclosing !== 'func') {
|
|
272
|
+
keep.add(i); // top-level / class / interface / enum / object member
|
|
273
|
+
}
|
|
274
|
+
else if (DECL_OPEN.test(trimmed)) {
|
|
275
|
+
keep.add(i); // a nested type declaration inside a body
|
|
276
|
+
}
|
|
277
|
+
else if (PURE_CLOSE.test(trimmed)) {
|
|
278
|
+
keep.add(i); // structural closer
|
|
279
|
+
}
|
|
280
|
+
else if (tokens.length > 0 && queryOverlap(trimmed, tokens) > 0) {
|
|
281
|
+
keep.add(i); // query-relevant body line
|
|
282
|
+
}
|
|
283
|
+
applyLineToStack(raw, state, stack);
|
|
284
|
+
}
|
|
285
|
+
const body = elide(lines, keep);
|
|
286
|
+
return finalizeLossy({
|
|
287
|
+
original: text,
|
|
288
|
+
body,
|
|
289
|
+
contentType: EContentType.SourceCode,
|
|
290
|
+
strategy: ECompressionStrategy.Code,
|
|
291
|
+
opts,
|
|
292
|
+
note: `code outline: ${lines.length} lines (function bodies elided)`,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ICompressionResult } from './result/compression-result.js';
|
|
2
|
+
import type { ICompressOptions } from './result/compress-options.js';
|
|
3
|
+
/**
|
|
4
|
+
* Route a blob to the right deterministic compressor and return the result.
|
|
5
|
+
* This is the one entry point the `shrk compress` CLI and the
|
|
6
|
+
* `compress_context` MCP tool call. Content type is auto-detected unless
|
|
7
|
+
* forced via `opts.contentType`. Pure — no model, no network; the same bytes
|
|
8
|
+
* and options always yield the same output.
|
|
9
|
+
*/
|
|
10
|
+
export declare function compressContent(text: string, opts?: ICompressOptions): ICompressionResult;
|
|
11
|
+
//# sourceMappingURL=compress-content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compress-content.d.ts","sourceRoot":"","sources":["../src/compress-content.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAWrE;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,kBAAkB,CA4B7F"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { EContentType } from "./content/content-type.js";
|
|
2
|
+
import { detectContentType } from "./content/detect-content-type.js";
|
|
3
|
+
import { segmentContent, isRichSegmentType } from "./content/segment.js";
|
|
4
|
+
import { ECompressionStrategy } from "./result/compression-strategy.js";
|
|
5
|
+
import { measureSavings } from "./tokens/estimate-tokens.js";
|
|
6
|
+
import { compressJson } from "./json/compress-json.js";
|
|
7
|
+
import { compressLog } from "./text/compress-log.js";
|
|
8
|
+
import { compressSearch } from "./text/compress-search.js";
|
|
9
|
+
import { compressDiff } from "./text/compress-diff.js";
|
|
10
|
+
import { compressLines } from "./text/compress-lines.js";
|
|
11
|
+
import { compressMarkdown } from "./text/compress-markdown.js";
|
|
12
|
+
import { compressCode } from "./code/compress-code.js";
|
|
13
|
+
/**
|
|
14
|
+
* Route a blob to the right deterministic compressor and return the result.
|
|
15
|
+
* This is the one entry point the `shrk compress` CLI and the
|
|
16
|
+
* `compress_context` MCP tool call. Content type is auto-detected unless
|
|
17
|
+
* forced via `opts.contentType`. Pure — no model, no network; the same bytes
|
|
18
|
+
* and options always yield the same output.
|
|
19
|
+
*/
|
|
20
|
+
export function compressContent(text, opts = {}) {
|
|
21
|
+
const type = opts.contentType ?? detectContentType(text);
|
|
22
|
+
switch (type) {
|
|
23
|
+
case EContentType.JsonArray:
|
|
24
|
+
case EContentType.Json:
|
|
25
|
+
return compressJson(text, opts);
|
|
26
|
+
case EContentType.GitDiff:
|
|
27
|
+
return compressDiff(text, opts);
|
|
28
|
+
case EContentType.SearchResults:
|
|
29
|
+
return compressSearch(text, opts);
|
|
30
|
+
case EContentType.BuildLog:
|
|
31
|
+
return compressLog(text, opts);
|
|
32
|
+
case EContentType.SourceCode:
|
|
33
|
+
return compressCode(text, opts);
|
|
34
|
+
case EContentType.Markdown:
|
|
35
|
+
return compressMarkdown(text, opts);
|
|
36
|
+
case EContentType.PlainText:
|
|
37
|
+
default:
|
|
38
|
+
// P4.3: a blob that didn't match one clean type may still be a MIX of
|
|
39
|
+
// types (prose + a JSON block + a stack trace). Segment and compress each
|
|
40
|
+
// run with its own strategy. Only the catch-all PlainText path tries this,
|
|
41
|
+
// so every single-type route above is byte-identical to before.
|
|
42
|
+
if (!opts.contentType) {
|
|
43
|
+
const mixed = compressMixed(text, opts);
|
|
44
|
+
if (mixed)
|
|
45
|
+
return mixed;
|
|
46
|
+
}
|
|
47
|
+
return compressLines(text, type, opts);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Compress a mixed blob by segmenting it and routing each run to its own
|
|
52
|
+
* compressor, then reassembling. Returns null when the blob is effectively
|
|
53
|
+
* single-type (≤1 rich segment) or the segmented result doesn't beat plain
|
|
54
|
+
* line dedup — so the caller falls back to {@link compressLines}.
|
|
55
|
+
*/
|
|
56
|
+
function compressMixed(text, opts) {
|
|
57
|
+
const segments = segmentContent(text);
|
|
58
|
+
if (segments.length < 2 || !segments.some((s) => isRichSegmentType(s.type)))
|
|
59
|
+
return null;
|
|
60
|
+
let anyLossy = false;
|
|
61
|
+
const parts = segments.map((seg) => {
|
|
62
|
+
const r = compressContent(seg.text, { ...opts, contentType: seg.type });
|
|
63
|
+
if (r.lossy)
|
|
64
|
+
anyLossy = true;
|
|
65
|
+
return r.compressed;
|
|
66
|
+
});
|
|
67
|
+
const reassembled = parts.join('\n');
|
|
68
|
+
const savings = measureSavings(text, reassembled, EContentType.PlainText);
|
|
69
|
+
if (savings.after >= savings.before)
|
|
70
|
+
return null; // line dedup may still win
|
|
71
|
+
return {
|
|
72
|
+
compressed: reassembled,
|
|
73
|
+
contentType: EContentType.PlainText,
|
|
74
|
+
strategy: ECompressionStrategy.Mixed,
|
|
75
|
+
savings,
|
|
76
|
+
lossy: anyLossy,
|
|
77
|
+
note: `mixed: ${segments.length} segments (${segments.map((s) => s.type).join(', ')})`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coarse content classes the router recognises. The class selects which
|
|
3
|
+
* deterministic compressor runs. Ordered loosely from most-specific
|
|
4
|
+
* (cheapest to over-trigger) to least.
|
|
5
|
+
*/
|
|
6
|
+
export declare enum EContentType {
|
|
7
|
+
/** A JSON array (top-level `[ ... ]`). The table compactor's prime target. */
|
|
8
|
+
JsonArray = "json-array",
|
|
9
|
+
/** A JSON object or scalar (top-level `{ ... }` / value). */
|
|
10
|
+
Json = "json",
|
|
11
|
+
/** A unified/`git` diff. */
|
|
12
|
+
GitDiff = "git-diff",
|
|
13
|
+
/** grep/ripgrep `file:line:` style search output. */
|
|
14
|
+
SearchResults = "search-results",
|
|
15
|
+
/** Build / test / runtime log output. */
|
|
16
|
+
BuildLog = "build-log",
|
|
17
|
+
/** Source code in a recognised language. */
|
|
18
|
+
SourceCode = "source-code",
|
|
19
|
+
/** Markdown prose / docs. */
|
|
20
|
+
Markdown = "markdown",
|
|
21
|
+
/** YAML configuration / manifests (`key: value` mappings + `- ` lists). */
|
|
22
|
+
Yaml = "yaml",
|
|
23
|
+
/** Delimiter-separated values (CSV / TSV): a stable column count per line. */
|
|
24
|
+
Csv = "csv",
|
|
25
|
+
/** Anything else. */
|
|
26
|
+
PlainText = "plain-text"
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=content-type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-type.d.ts","sourceRoot":"","sources":["../../src/content/content-type.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,oBAAY,YAAY;IACtB,8EAA8E;IAC9E,SAAS,eAAe;IACxB,6DAA6D;IAC7D,IAAI,SAAS;IACb,4BAA4B;IAC5B,OAAO,aAAa;IACpB,qDAAqD;IACrD,aAAa,mBAAmB;IAChC,yCAAyC;IACzC,QAAQ,cAAc;IACtB,4CAA4C;IAC5C,UAAU,gBAAgB;IAC1B,6BAA6B;IAC7B,QAAQ,aAAa;IACrB,2EAA2E;IAC3E,IAAI,SAAS;IACb,8EAA8E;IAC9E,GAAG,QAAQ;IACX,qBAAqB;IACrB,SAAS,eAAe;CACzB"}
|