@blackwell-systems/gcf 0.1.0
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 +177 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +122 -0
- package/dist/cli.js.map +1 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +43 -0
- package/dist/constants.js.map +1 -0
- package/dist/decode.d.ts +6 -0
- package/dist/decode.d.ts.map +1 -0
- package/dist/decode.js +179 -0
- package/dist/decode.js.map +1 -0
- package/dist/delta.d.ts +6 -0
- package/dist/delta.d.ts.map +1 -0
- package/dist/delta.js +46 -0
- package/dist/delta.js.map +1 -0
- package/dist/encode.d.ts +6 -0
- package/dist/encode.d.ts.map +1 -0
- package/dist/encode.js +69 -0
- package/dist/encode.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/session.d.ts +31 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +127 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +51 -0
- package/src/cli.ts +136 -0
- package/src/constants.ts +43 -0
- package/src/decode.ts +208 -0
- package/src/delta.ts +55 -0
- package/src/encode.ts +84 -0
- package/src/index.ts +6 -0
- package/src/session.ts +147 -0
- package/src/types.ts +79 -0
package/dist/encode.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../src/encode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAU,MAAM,YAAY,CAAC;AAyBlD;;GAEG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAuDzC"}
|
package/dist/encode.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { KIND_ABBREV } from './constants.js';
|
|
2
|
+
function groupByDistance(symbols) {
|
|
3
|
+
if (symbols.length === 0)
|
|
4
|
+
return [];
|
|
5
|
+
const groups = [];
|
|
6
|
+
let current = null;
|
|
7
|
+
for (const s of symbols) {
|
|
8
|
+
if (current === null || current.distance !== s.distance) {
|
|
9
|
+
current = { distance: s.distance, symbols: [] };
|
|
10
|
+
groups.push(current);
|
|
11
|
+
}
|
|
12
|
+
current.symbols.push(s);
|
|
13
|
+
}
|
|
14
|
+
return groups;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Encode serializes a Payload into GCF text format.
|
|
18
|
+
*/
|
|
19
|
+
export function encode(p) {
|
|
20
|
+
const lines = [];
|
|
21
|
+
// Header line.
|
|
22
|
+
let header = `GCF tool=${p.tool} budget=${p.tokenBudget} tokens=${p.tokensUsed} symbols=${p.symbols.length}`;
|
|
23
|
+
if (p.packRoot) {
|
|
24
|
+
header += ` pack_root=${p.packRoot}`;
|
|
25
|
+
}
|
|
26
|
+
lines.push(header);
|
|
27
|
+
// Build symbol index for edge references.
|
|
28
|
+
const symIndex = new Map();
|
|
29
|
+
for (let i = 0; i < p.symbols.length; i++) {
|
|
30
|
+
symIndex.set(p.symbols[i].qualifiedName, i);
|
|
31
|
+
}
|
|
32
|
+
// Group symbols by distance.
|
|
33
|
+
const groups = groupByDistance(p.symbols);
|
|
34
|
+
const groupNames = ['targets', 'related', 'extended'];
|
|
35
|
+
for (const g of groups) {
|
|
36
|
+
if (g.symbols.length === 0)
|
|
37
|
+
continue;
|
|
38
|
+
let name;
|
|
39
|
+
if (g.distance < groupNames.length) {
|
|
40
|
+
name = groupNames[g.distance];
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
name = `distance_${g.distance}`;
|
|
44
|
+
}
|
|
45
|
+
lines.push(`## ${name}`);
|
|
46
|
+
for (const s of g.symbols) {
|
|
47
|
+
const idx = symIndex.get(s.qualifiedName);
|
|
48
|
+
const kind = KIND_ABBREV[s.kind] || s.kind;
|
|
49
|
+
lines.push(`@${idx} ${kind} ${s.qualifiedName} ${s.score.toFixed(2)} ${s.provenance}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Edges section.
|
|
53
|
+
if (p.edges.length > 0) {
|
|
54
|
+
lines.push('## edges');
|
|
55
|
+
for (const e of p.edges) {
|
|
56
|
+
const srcIdx = symIndex.get(e.source);
|
|
57
|
+
const tgtIdx = symIndex.get(e.target);
|
|
58
|
+
if (srcIdx === undefined || tgtIdx === undefined)
|
|
59
|
+
continue;
|
|
60
|
+
let line = `@${tgtIdx}<@${srcIdx} ${e.edgeType}`;
|
|
61
|
+
if (e.status && e.status !== 'unchanged') {
|
|
62
|
+
line += ` ${e.status}`;
|
|
63
|
+
}
|
|
64
|
+
lines.push(line);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return lines.join('\n') + '\n';
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=encode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encode.js","sourceRoot":"","sources":["../src/encode.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { Symbol, Edge, Payload, DeltaPayload, Components } from './types.js';
|
|
2
|
+
export { KIND_ABBREV, KIND_EXPAND } from './constants.js';
|
|
3
|
+
export { encode } from './encode.js';
|
|
4
|
+
export { decode } from './decode.js';
|
|
5
|
+
export { Session, encodeWithSession } from './session.js';
|
|
6
|
+
export { encodeDelta } from './delta.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { KIND_ABBREV, KIND_EXPAND } from './constants.js';
|
|
2
|
+
export { encode } from './encode.js';
|
|
3
|
+
export { decode } from './decode.js';
|
|
4
|
+
export { Session, encodeWithSession } from './session.js';
|
|
5
|
+
export { encodeDelta } from './delta.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Payload, Symbol } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Session tracks symbols that have been transmitted to a client, enabling
|
|
4
|
+
* subsequent responses to reference them by ID without full retransmission.
|
|
5
|
+
* This makes multi-call workflows progressively cheaper.
|
|
6
|
+
*/
|
|
7
|
+
export declare class Session {
|
|
8
|
+
private symbols;
|
|
9
|
+
private nextID;
|
|
10
|
+
/** Returns true if the symbol has been sent in a previous response. */
|
|
11
|
+
transmitted(qname: string): boolean;
|
|
12
|
+
/** Returns the session-global ID for a previously transmitted symbol, or -1 if not found. */
|
|
13
|
+
getID(qname: string): number;
|
|
14
|
+
/**
|
|
15
|
+
* Record marks symbols as transmitted and assigns session-global IDs.
|
|
16
|
+
* Call this after a successful encode to register newly-sent symbols.
|
|
17
|
+
*/
|
|
18
|
+
record(symbols: Symbol[]): void;
|
|
19
|
+
/** Returns the number of symbols tracked in this session. */
|
|
20
|
+
size(): number;
|
|
21
|
+
/** Clears the session state. */
|
|
22
|
+
reset(): void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Encode a payload using GCF with session deduplication.
|
|
26
|
+
* Symbols that were already transmitted in prior responses are emitted as
|
|
27
|
+
* bare references (`@N # previously transmitted`) instead of full declarations.
|
|
28
|
+
* After encoding, newly-sent symbols are recorded in the session.
|
|
29
|
+
*/
|
|
30
|
+
export declare function encodeWithSession(p: Payload, sess: Session | null): string;
|
|
31
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAIlD;;;;GAIG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,MAAM,CAAa;IAE3B,uEAAuE;IACvE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAInC,6FAA6F;IAC7F,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAK5B;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAS/B,6DAA6D;IAC7D,IAAI,IAAI,MAAM;IAId,gCAAgC;IAChC,KAAK,IAAI,IAAI;CAId;AAqBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,MAAM,CAwE1E"}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { KIND_ABBREV } from './constants.js';
|
|
2
|
+
import { encode } from './encode.js';
|
|
3
|
+
/**
|
|
4
|
+
* Session tracks symbols that have been transmitted to a client, enabling
|
|
5
|
+
* subsequent responses to reference them by ID without full retransmission.
|
|
6
|
+
* This makes multi-call workflows progressively cheaper.
|
|
7
|
+
*/
|
|
8
|
+
export class Session {
|
|
9
|
+
symbols = new Map();
|
|
10
|
+
nextID = 0;
|
|
11
|
+
/** Returns true if the symbol has been sent in a previous response. */
|
|
12
|
+
transmitted(qname) {
|
|
13
|
+
return this.symbols.has(qname);
|
|
14
|
+
}
|
|
15
|
+
/** Returns the session-global ID for a previously transmitted symbol, or -1 if not found. */
|
|
16
|
+
getID(qname) {
|
|
17
|
+
const id = this.symbols.get(qname);
|
|
18
|
+
return id !== undefined ? id : -1;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Record marks symbols as transmitted and assigns session-global IDs.
|
|
22
|
+
* Call this after a successful encode to register newly-sent symbols.
|
|
23
|
+
*/
|
|
24
|
+
record(symbols) {
|
|
25
|
+
for (const sym of symbols) {
|
|
26
|
+
if (!this.symbols.has(sym.qualifiedName)) {
|
|
27
|
+
this.symbols.set(sym.qualifiedName, this.nextID);
|
|
28
|
+
this.nextID++;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Returns the number of symbols tracked in this session. */
|
|
33
|
+
size() {
|
|
34
|
+
return this.symbols.size;
|
|
35
|
+
}
|
|
36
|
+
/** Clears the session state. */
|
|
37
|
+
reset() {
|
|
38
|
+
this.symbols.clear();
|
|
39
|
+
this.nextID = 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function groupByDistance(symbols) {
|
|
43
|
+
if (symbols.length === 0)
|
|
44
|
+
return [];
|
|
45
|
+
const groups = [];
|
|
46
|
+
let current = null;
|
|
47
|
+
for (const s of symbols) {
|
|
48
|
+
if (current === null || current.distance !== s.distance) {
|
|
49
|
+
current = { distance: s.distance, symbols: [] };
|
|
50
|
+
groups.push(current);
|
|
51
|
+
}
|
|
52
|
+
current.symbols.push(s);
|
|
53
|
+
}
|
|
54
|
+
return groups;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Encode a payload using GCF with session deduplication.
|
|
58
|
+
* Symbols that were already transmitted in prior responses are emitted as
|
|
59
|
+
* bare references (`@N # previously transmitted`) instead of full declarations.
|
|
60
|
+
* After encoding, newly-sent symbols are recorded in the session.
|
|
61
|
+
*/
|
|
62
|
+
export function encodeWithSession(p, sess) {
|
|
63
|
+
if (!sess) {
|
|
64
|
+
return encode(p);
|
|
65
|
+
}
|
|
66
|
+
const lines = [];
|
|
67
|
+
// Header with session=true marker.
|
|
68
|
+
let header = `GCF tool=${p.tool} budget=${p.tokenBudget} tokens=${p.tokensUsed} symbols=${p.symbols.length} session=true`;
|
|
69
|
+
if (p.packRoot) {
|
|
70
|
+
header += ` pack_root=${p.packRoot}`;
|
|
71
|
+
}
|
|
72
|
+
lines.push(header);
|
|
73
|
+
// Build local ID mapping for this response.
|
|
74
|
+
const localIndex = new Map();
|
|
75
|
+
for (let i = 0; i < p.symbols.length; i++) {
|
|
76
|
+
localIndex.set(p.symbols[i].qualifiedName, i);
|
|
77
|
+
}
|
|
78
|
+
// Track which symbols are new for recording after encode.
|
|
79
|
+
const newSymbols = [];
|
|
80
|
+
// Group by distance.
|
|
81
|
+
const groups = groupByDistance(p.symbols);
|
|
82
|
+
const groupNames = ['targets', 'related', 'extended'];
|
|
83
|
+
for (const g of groups) {
|
|
84
|
+
if (g.symbols.length === 0)
|
|
85
|
+
continue;
|
|
86
|
+
let name;
|
|
87
|
+
if (g.distance < groupNames.length) {
|
|
88
|
+
name = groupNames[g.distance];
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
name = `distance_${g.distance}`;
|
|
92
|
+
}
|
|
93
|
+
lines.push(`## ${name}`);
|
|
94
|
+
for (const s of g.symbols) {
|
|
95
|
+
const idx = localIndex.get(s.qualifiedName);
|
|
96
|
+
if (sess.transmitted(s.qualifiedName)) {
|
|
97
|
+
// Bare reference: symbol was sent in a prior response.
|
|
98
|
+
lines.push(`@${idx} # previously transmitted`);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// Full declaration.
|
|
102
|
+
const kind = KIND_ABBREV[s.kind] || s.kind;
|
|
103
|
+
lines.push(`@${idx} ${kind} ${s.qualifiedName} ${s.score.toFixed(2)} ${s.provenance}`);
|
|
104
|
+
newSymbols.push(s);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Edges section.
|
|
109
|
+
if (p.edges.length > 0) {
|
|
110
|
+
lines.push('## edges');
|
|
111
|
+
for (const e of p.edges) {
|
|
112
|
+
const srcIdx = localIndex.get(e.source);
|
|
113
|
+
const tgtIdx = localIndex.get(e.target);
|
|
114
|
+
if (srcIdx === undefined || tgtIdx === undefined)
|
|
115
|
+
continue;
|
|
116
|
+
let line = `@${tgtIdx}<@${srcIdx} ${e.edgeType}`;
|
|
117
|
+
if (e.status && e.status !== 'unchanged') {
|
|
118
|
+
line += ` ${e.status}`;
|
|
119
|
+
}
|
|
120
|
+
lines.push(line);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Record all new symbols in the session.
|
|
124
|
+
sess.record(newSymbols);
|
|
125
|
+
return lines.join('\n') + '\n';
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symbol represents a node in a GCF payload.
|
|
3
|
+
*/
|
|
4
|
+
export interface Symbol {
|
|
5
|
+
/** Fully qualified identifier (e.g., "pkg/auth.Middleware") */
|
|
6
|
+
qualifiedName: string;
|
|
7
|
+
/** Node type: "function", "type", "method", etc. */
|
|
8
|
+
kind: string;
|
|
9
|
+
/** Relevance score (0.0 to 1.0) */
|
|
10
|
+
score: number;
|
|
11
|
+
/** Discovery method: "lsp_resolved", "ast_inferred", etc. */
|
|
12
|
+
provenance: string;
|
|
13
|
+
/** Hops from query center (0=target, 1=related, 2+=extended) */
|
|
14
|
+
distance: number;
|
|
15
|
+
/** Optional: function/method signature */
|
|
16
|
+
signature?: string;
|
|
17
|
+
/** Optional: score breakdown */
|
|
18
|
+
components?: Components;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Components holds the score breakdown for a symbol.
|
|
22
|
+
*/
|
|
23
|
+
export interface Components {
|
|
24
|
+
blastRadius: number;
|
|
25
|
+
confidence: number;
|
|
26
|
+
recency: number;
|
|
27
|
+
distance: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Edge represents a directed relationship in a GCF payload.
|
|
31
|
+
*/
|
|
32
|
+
export interface Edge {
|
|
33
|
+
/** Qualified name of source symbol */
|
|
34
|
+
source: string;
|
|
35
|
+
/** Qualified name of target symbol */
|
|
36
|
+
target: string;
|
|
37
|
+
/** Relationship type (e.g., "calls", "imports", "implements") */
|
|
38
|
+
edgeType: string;
|
|
39
|
+
/** Optional: "added", "removed", "unchanged" (for diff responses) */
|
|
40
|
+
status?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Payload is the input/output structure for GCF encoding/decoding.
|
|
44
|
+
*/
|
|
45
|
+
export interface Payload {
|
|
46
|
+
/** Producing tool name (e.g., "context_for_task") */
|
|
47
|
+
tool: string;
|
|
48
|
+
/** Token budget requested by the consumer */
|
|
49
|
+
tokenBudget: number;
|
|
50
|
+
/** Actual tokens consumed by this payload */
|
|
51
|
+
tokensUsed: number;
|
|
52
|
+
/** Content-addressed identity (hex SHA-256), enables delta encoding */
|
|
53
|
+
packRoot?: string;
|
|
54
|
+
/** Ordered by score descending within each distance group */
|
|
55
|
+
symbols: Symbol[];
|
|
56
|
+
/** Directed relationships between symbols */
|
|
57
|
+
edges: Edge[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* DeltaPayload represents the diff between a prior context pack and the
|
|
61
|
+
* current result. Used for incremental context delivery.
|
|
62
|
+
*/
|
|
63
|
+
export interface DeltaPayload {
|
|
64
|
+
tool: string;
|
|
65
|
+
/** pack_root the consumer has */
|
|
66
|
+
baseRoot: string;
|
|
67
|
+
/** pack_root of the current result */
|
|
68
|
+
newRoot: string;
|
|
69
|
+
removed: Symbol[];
|
|
70
|
+
added: Symbol[];
|
|
71
|
+
removedEdges: Edge[];
|
|
72
|
+
addedEdges: Edge[];
|
|
73
|
+
deltaTokens: number;
|
|
74
|
+
fullTokens: number;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,+DAA+D;IAC/D,aAAa,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6CAA6C;IAC7C,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,EAAE,IAAI,EAAE,CAAC;IACrB,UAAU,EAAE,IAAI,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blackwell-systems/gcf",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript implementation of GCF (Graph Compact Format) - token-optimized wire format for LLM tool responses",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"gcf": "./dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src",
|
|
20
|
+
"LICENSE",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"prepublishOnly": "tsc"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"gcf",
|
|
31
|
+
"graph",
|
|
32
|
+
"compact",
|
|
33
|
+
"format",
|
|
34
|
+
"llm",
|
|
35
|
+
"tokens",
|
|
36
|
+
"mcp",
|
|
37
|
+
"wire-format"
|
|
38
|
+
],
|
|
39
|
+
"author": "Blackwell Systems",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/blackwell-systems/gcf-typescript.git"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/blackwell-systems/gcf",
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^22.0.0",
|
|
48
|
+
"typescript": "^5.4.0",
|
|
49
|
+
"vitest": "^2.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* GCF command-line interface: encode, decode, stats.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
import { encode } from './encode.js';
|
|
8
|
+
import { decode } from './decode.js';
|
|
9
|
+
import type { Payload, Symbol, Edge } from './types.js';
|
|
10
|
+
|
|
11
|
+
const USAGE = `gcf - token-optimized wire format for LLM tool responses
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
gcf encode [file] Encode JSON payload to GCF (stdin if no file)
|
|
15
|
+
gcf decode [file] Decode GCF text to JSON (stdin if no file)
|
|
16
|
+
gcf stats [file] Compare token counts: JSON vs GCF (stdin if no file)
|
|
17
|
+
gcf version Print version
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
gcf encode < payload.json
|
|
21
|
+
gcf decode < payload.gcf
|
|
22
|
+
gcf stats payload.json
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
function readInput(args: string[]): string {
|
|
26
|
+
if (args.length > 0 && args[0] !== '-') {
|
|
27
|
+
return readFileSync(args[0]!, 'utf-8');
|
|
28
|
+
}
|
|
29
|
+
return readFileSync(0, 'utf-8');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function payloadFromJSON(data: string): Payload {
|
|
33
|
+
const obj = JSON.parse(data);
|
|
34
|
+
return {
|
|
35
|
+
tool: obj.tool ?? '',
|
|
36
|
+
tokenBudget: obj.tokenBudget ?? 0,
|
|
37
|
+
tokensUsed: obj.tokensUsed ?? 0,
|
|
38
|
+
packRoot: obj.packRoot ?? '',
|
|
39
|
+
symbols: (obj.symbols ?? []).map((s: any) => ({
|
|
40
|
+
qualifiedName: s.qualifiedName,
|
|
41
|
+
kind: s.kind,
|
|
42
|
+
score: s.score,
|
|
43
|
+
provenance: s.provenance,
|
|
44
|
+
distance: s.distance ?? 0,
|
|
45
|
+
})),
|
|
46
|
+
edges: (obj.edges ?? []).map((e: any) => ({
|
|
47
|
+
source: e.source,
|
|
48
|
+
target: e.target,
|
|
49
|
+
edgeType: e.edgeType,
|
|
50
|
+
status: e.status ?? '',
|
|
51
|
+
})),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function payloadToJSON(p: Payload): string {
|
|
56
|
+
return JSON.stringify({
|
|
57
|
+
tool: p.tool,
|
|
58
|
+
tokensUsed: p.tokensUsed,
|
|
59
|
+
tokenBudget: p.tokenBudget,
|
|
60
|
+
packRoot: p.packRoot ?? '',
|
|
61
|
+
symbols: p.symbols.map(s => ({
|
|
62
|
+
qualifiedName: s.qualifiedName,
|
|
63
|
+
kind: s.kind,
|
|
64
|
+
score: s.score,
|
|
65
|
+
provenance: s.provenance,
|
|
66
|
+
distance: s.distance,
|
|
67
|
+
})),
|
|
68
|
+
edges: p.edges.map(e => ({
|
|
69
|
+
source: e.source,
|
|
70
|
+
target: e.target,
|
|
71
|
+
edgeType: e.edgeType,
|
|
72
|
+
...(e.status ? { status: e.status } : {}),
|
|
73
|
+
})),
|
|
74
|
+
}, null, 2);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function doEncode(data: string): void {
|
|
78
|
+
const p = payloadFromJSON(data);
|
|
79
|
+
process.stdout.write(encode(p));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function doDecode(data: string): void {
|
|
83
|
+
const p = decode(data);
|
|
84
|
+
console.log(payloadToJSON(p));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function doStats(data: string): void {
|
|
88
|
+
const p = payloadFromJSON(data);
|
|
89
|
+
const gcfOutput = encode(p);
|
|
90
|
+
|
|
91
|
+
const jsonTokens = Math.floor(data.trim().length / 4);
|
|
92
|
+
const gcfTokens = Math.floor(gcfOutput.trim().length / 4);
|
|
93
|
+
|
|
94
|
+
const savings = jsonTokens > 0 ? 100 * (1 - gcfTokens / jsonTokens) : 0;
|
|
95
|
+
|
|
96
|
+
const barWidth = 30;
|
|
97
|
+
const jsonBar = '█'.repeat(barWidth);
|
|
98
|
+
const gcfFilled = jsonTokens > 0 ? Math.round((gcfTokens * barWidth) / jsonTokens) : 0;
|
|
99
|
+
const gcfBar = '█'.repeat(gcfFilled) + '░'.repeat(barWidth - gcfFilled);
|
|
100
|
+
|
|
101
|
+
console.log(`Payload: ${p.symbols.length} symbols, ${p.edges.length} edges\n`);
|
|
102
|
+
console.log(` JSON ${jsonBar} ${jsonTokens} tokens`);
|
|
103
|
+
console.log(` GCF ${gcfBar} ${gcfTokens} tokens`);
|
|
104
|
+
console.log(`\n Savings: ${Math.round(savings)}% fewer tokens with GCF`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const args = process.argv.slice(2);
|
|
108
|
+
const cmd = args[0];
|
|
109
|
+
|
|
110
|
+
switch (cmd) {
|
|
111
|
+
case 'encode':
|
|
112
|
+
doEncode(readInput(args.slice(1)));
|
|
113
|
+
break;
|
|
114
|
+
case 'decode':
|
|
115
|
+
doDecode(readInput(args.slice(1)));
|
|
116
|
+
break;
|
|
117
|
+
case 'stats':
|
|
118
|
+
doStats(readInput(args.slice(1)));
|
|
119
|
+
break;
|
|
120
|
+
case 'version':
|
|
121
|
+
console.log('gcf 0.1.0');
|
|
122
|
+
break;
|
|
123
|
+
case '-h':
|
|
124
|
+
case '--help':
|
|
125
|
+
case 'help':
|
|
126
|
+
process.stdout.write(USAGE);
|
|
127
|
+
break;
|
|
128
|
+
default:
|
|
129
|
+
if (!cmd) {
|
|
130
|
+
process.stderr.write(USAGE);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
process.stderr.write(`unknown command: ${cmd}\n\n`);
|
|
134
|
+
process.stderr.write(USAGE);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KindAbbrev maps full kind names to short GCF abbreviations.
|
|
3
|
+
*/
|
|
4
|
+
export const KIND_ABBREV: Record<string, string> = {
|
|
5
|
+
function: 'fn',
|
|
6
|
+
type: 'type',
|
|
7
|
+
method: 'method',
|
|
8
|
+
interface: 'iface',
|
|
9
|
+
var: 'var',
|
|
10
|
+
const: 'const',
|
|
11
|
+
resource: 'resource',
|
|
12
|
+
table: 'table',
|
|
13
|
+
class: 'class',
|
|
14
|
+
selector: 'selector',
|
|
15
|
+
field: 'field',
|
|
16
|
+
route_handler: 'route',
|
|
17
|
+
external: 'ext',
|
|
18
|
+
file: 'file',
|
|
19
|
+
package: 'pkg',
|
|
20
|
+
service: 'svc',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* KindExpand is the reverse of KindAbbrev: maps abbreviations back to full kind names.
|
|
25
|
+
*/
|
|
26
|
+
export const KIND_EXPAND: Record<string, string> = {
|
|
27
|
+
fn: 'function',
|
|
28
|
+
type: 'type',
|
|
29
|
+
method: 'method',
|
|
30
|
+
iface: 'interface',
|
|
31
|
+
var: 'var',
|
|
32
|
+
const: 'const',
|
|
33
|
+
resource: 'resource',
|
|
34
|
+
table: 'table',
|
|
35
|
+
class: 'class',
|
|
36
|
+
selector: 'selector',
|
|
37
|
+
field: 'field',
|
|
38
|
+
route: 'route_handler',
|
|
39
|
+
ext: 'external',
|
|
40
|
+
file: 'file',
|
|
41
|
+
pkg: 'package',
|
|
42
|
+
svc: 'service',
|
|
43
|
+
};
|