@contextgit/core 0.0.3
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/dist/embeddings.d.ts +30 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +65 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/embeddings.test.d.ts +2 -0
- package/dist/embeddings.test.d.ts.map +1 -0
- package/dist/embeddings.test.js +52 -0
- package/dist/embeddings.test.js.map +1 -0
- package/dist/engine.d.ts +124 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +175 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/snapshot.d.ts +5 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +64 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/summarizer.d.ts +33 -0
- package/dist/summarizer.d.ts.map +1 -0
- package/dist/summarizer.js +78 -0
- package/dist/summarizer.js.map +1 -0
- package/dist/summarizer.test.d.ts +2 -0
- package/dist/summarizer.test.d.ts.map +1 -0
- package/dist/summarizer.test.js +97 -0
- package/dist/summarizer.test.js.map +1 -0
- package/dist/threads.d.ts +14 -0
- package/dist/threads.d.ts.map +1 -0
- package/dist/threads.js +23 -0
- package/dist/threads.js.map +1 -0
- package/dist/types.d.ts +163 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +29 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type PipelineFn = (text: string, options: {
|
|
2
|
+
pooling: string;
|
|
3
|
+
normalize: boolean;
|
|
4
|
+
}) => Promise<{
|
|
5
|
+
data: Float32Array;
|
|
6
|
+
}>;
|
|
7
|
+
export interface EmbeddingServiceOptions {
|
|
8
|
+
/** Override the pipeline factory — for tests. */
|
|
9
|
+
pipelineFactory?: (task: string, model: string) => Promise<PipelineFn>;
|
|
10
|
+
}
|
|
11
|
+
export declare class EmbeddingService {
|
|
12
|
+
private pipeline;
|
|
13
|
+
private loadPromise;
|
|
14
|
+
private readonly pipelineFactory;
|
|
15
|
+
static readonly MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
16
|
+
static readonly DIMS = 384;
|
|
17
|
+
constructor(options?: EmbeddingServiceOptions);
|
|
18
|
+
/**
|
|
19
|
+
* Generate a 384-dim embedding for `text`.
|
|
20
|
+
* Returns null if the model is unavailable or any error occurs.
|
|
21
|
+
*/
|
|
22
|
+
embed(text: string): Promise<Float32Array | null>;
|
|
23
|
+
/** True once the model has been loaded at least once (even if it failed). */
|
|
24
|
+
get isReady(): boolean;
|
|
25
|
+
private ensureLoaded;
|
|
26
|
+
private load;
|
|
27
|
+
private static defaultPipelineFactory;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=embeddings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../src/embeddings.ts"],"names":[],"mappings":"AAUA,KAAK,UAAU,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,KAAK,OAAO,CAAC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAA;AAErH,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;CACvE;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsD;IAEtF,MAAM,CAAC,QAAQ,CAAC,KAAK,6BAA4B;IACjD,MAAM,CAAC,QAAQ,CAAC,IAAI,OAAO;gBAEf,OAAO,GAAE,uBAA4B;IAIjD;;;OAGG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAWvD,6EAA6E;IAC7E,IAAI,OAAO,IAAI,OAAO,CAErB;YAEa,YAAY;YAQZ,IAAI;mBAQG,sBAAsB;CAS5C"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// EmbeddingService — generates 384-dim sentence embeddings using
|
|
2
|
+
// @xenova/transformers (all-MiniLM-L6-v2, runs fully local, no API key).
|
|
3
|
+
//
|
|
4
|
+
// Usage:
|
|
5
|
+
// const svc = new EmbeddingService()
|
|
6
|
+
// const vector = await svc.embed('some text') // Float32Array | null
|
|
7
|
+
//
|
|
8
|
+
// Load failure is silently swallowed — callers receive null and should fall
|
|
9
|
+
// back to full-text search. Never let embedding errors propagate outward.
|
|
10
|
+
export class EmbeddingService {
|
|
11
|
+
pipeline = null;
|
|
12
|
+
loadPromise = null;
|
|
13
|
+
pipelineFactory;
|
|
14
|
+
static MODEL = 'Xenova/all-MiniLM-L6-v2';
|
|
15
|
+
static DIMS = 384;
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.pipelineFactory = options.pipelineFactory ?? EmbeddingService.defaultPipelineFactory;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate a 384-dim embedding for `text`.
|
|
21
|
+
* Returns null if the model is unavailable or any error occurs.
|
|
22
|
+
*/
|
|
23
|
+
async embed(text) {
|
|
24
|
+
try {
|
|
25
|
+
await this.ensureLoaded();
|
|
26
|
+
if (!this.pipeline)
|
|
27
|
+
return null;
|
|
28
|
+
const result = await this.pipeline(text, { pooling: 'mean', normalize: true });
|
|
29
|
+
return result.data;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** True once the model has been loaded at least once (even if it failed). */
|
|
36
|
+
get isReady() {
|
|
37
|
+
return this.loadPromise !== null;
|
|
38
|
+
}
|
|
39
|
+
async ensureLoaded() {
|
|
40
|
+
if (this.pipeline)
|
|
41
|
+
return;
|
|
42
|
+
if (!this.loadPromise) {
|
|
43
|
+
this.loadPromise = this.load();
|
|
44
|
+
}
|
|
45
|
+
await this.loadPromise;
|
|
46
|
+
}
|
|
47
|
+
async load() {
|
|
48
|
+
try {
|
|
49
|
+
this.pipeline = await this.pipelineFactory('feature-extraction', EmbeddingService.MODEL);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
this.pipeline = null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
static async defaultPipelineFactory(_task, model) {
|
|
56
|
+
// Dynamic import so the heavy @xenova/transformers bundle is only loaded
|
|
57
|
+
// when embeddings are actually needed.
|
|
58
|
+
const { pipeline } = await import('@xenova/transformers');
|
|
59
|
+
// Cast task to any to avoid strict PipelineType enum mismatch — we always
|
|
60
|
+
// pass 'feature-extraction' which is valid at runtime.
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
|
+
return pipeline('feature-extraction', model);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=embeddings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../src/embeddings.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,yEAAyE;AACzE,EAAE;AACF,SAAS;AACT,uCAAuC;AACvC,yEAAyE;AACzE,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAS3E,MAAM,OAAO,gBAAgB;IACnB,QAAQ,GAAsB,IAAI,CAAA;IAClC,WAAW,GAAyB,IAAI,CAAA;IAC/B,eAAe,CAAsD;IAEtF,MAAM,CAAU,KAAK,GAAG,yBAAyB,CAAA;IACjD,MAAM,CAAU,IAAI,GAAI,GAAG,CAAA;IAE3B,YAAY,UAAmC,EAAE;QAC/C,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,gBAAgB,CAAC,sBAAsB,CAAA;IAC3F,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK,CAAC,IAAY;QACtB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,EAAE,CAAA;YACzB,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAA;YAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAC9E,OAAO,MAAM,CAAC,IAAI,CAAA;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,WAAW,KAAK,IAAI,CAAA;IAClC,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAM;QACzB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAChC,CAAC;QACD,MAAM,IAAI,CAAC,WAAW,CAAA;IACxB,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAA;QAC1F,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACtB,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,KAAa,EAAE,KAAa;QACtE,yEAAyE;QACzE,uCAAuC;QACvC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAA;QACzD,0EAA0E;QAC1E,uDAAuD;QACvD,8DAA8D;QAC9D,OAAO,QAAQ,CAAC,oBAA2B,EAAE,KAAK,CAA0B,CAAA;IAC9E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.test.d.ts","sourceRoot":"","sources":["../src/embeddings.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { EmbeddingService } from './embeddings.js';
|
|
3
|
+
// Fake pipeline that returns a predictable 384-dim vector
|
|
4
|
+
function makeFakePipeline() {
|
|
5
|
+
return async (_text, _opts) => ({
|
|
6
|
+
data: new Float32Array(384).fill(0.5),
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
function makeBrokenPipeline() {
|
|
10
|
+
return Promise.reject(new Error('model load failed'));
|
|
11
|
+
}
|
|
12
|
+
describe('EmbeddingService', () => {
|
|
13
|
+
it('returns a Float32Array of length 384 on success', async () => {
|
|
14
|
+
const svc = new EmbeddingService({
|
|
15
|
+
pipelineFactory: async () => makeFakePipeline(),
|
|
16
|
+
});
|
|
17
|
+
const vec = await svc.embed('hello world');
|
|
18
|
+
expect(vec).toBeInstanceOf(Float32Array);
|
|
19
|
+
expect(vec.length).toBe(384);
|
|
20
|
+
});
|
|
21
|
+
it('returns null when pipeline load fails', async () => {
|
|
22
|
+
const svc = new EmbeddingService({
|
|
23
|
+
pipelineFactory: async () => { throw new Error('load error'); },
|
|
24
|
+
});
|
|
25
|
+
const vec = await svc.embed('hello');
|
|
26
|
+
expect(vec).toBeNull();
|
|
27
|
+
});
|
|
28
|
+
it('returns null when pipeline call throws', async () => {
|
|
29
|
+
const svc = new EmbeddingService({
|
|
30
|
+
pipelineFactory: async () => {
|
|
31
|
+
return async () => { throw new Error('inference error'); };
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
const vec = await svc.embed('hello');
|
|
35
|
+
expect(vec).toBeNull();
|
|
36
|
+
});
|
|
37
|
+
it('never throws — always returns null on any error', async () => {
|
|
38
|
+
const svc = new EmbeddingService({
|
|
39
|
+
pipelineFactory: () => makeBrokenPipeline(),
|
|
40
|
+
});
|
|
41
|
+
await expect(svc.embed('anything')).resolves.toBeNull();
|
|
42
|
+
});
|
|
43
|
+
it('loads the pipeline only once across multiple embeds', async () => {
|
|
44
|
+
const factory = vi.fn(async () => makeFakePipeline());
|
|
45
|
+
const svc = new EmbeddingService({ pipelineFactory: factory });
|
|
46
|
+
await svc.embed('a');
|
|
47
|
+
await svc.embed('b');
|
|
48
|
+
await svc.embed('c');
|
|
49
|
+
expect(factory).toHaveBeenCalledTimes(1);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=embeddings.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.test.js","sourceRoot":"","sources":["../src/embeddings.test.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { AgentRole, Branch, Commit, CommitType, ContextScope, SearchResult, SessionSnapshot, WorkflowType } from './types.js';
|
|
2
|
+
import { RollingSummarizer } from './summarizer.js';
|
|
3
|
+
import { EmbeddingService } from './embeddings.js';
|
|
4
|
+
interface EngineBranchInput {
|
|
5
|
+
projectId: string;
|
|
6
|
+
name: string;
|
|
7
|
+
gitBranch: string;
|
|
8
|
+
parentBranchId?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface EngineStore {
|
|
11
|
+
getBranch(id: string): Promise<{
|
|
12
|
+
headCommitId?: string;
|
|
13
|
+
gitBranch?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
} | null>;
|
|
16
|
+
getCommit(id: string): Promise<{
|
|
17
|
+
summary: string;
|
|
18
|
+
} | null>;
|
|
19
|
+
createBranch(input: EngineBranchInput): Promise<Branch>;
|
|
20
|
+
createCommit(input: EngineCommitStoreInput): Promise<Commit>;
|
|
21
|
+
mergeBranch(sourceBranchId: string, targetBranchId: string, summary: string): Promise<Commit>;
|
|
22
|
+
getSessionSnapshot(projectId: string, branchId: string): Promise<SessionSnapshot>;
|
|
23
|
+
upsertAgent(agent: EngineAgentInput): Promise<unknown>;
|
|
24
|
+
indexEmbedding(commitId: string, vector: Float32Array): Promise<void>;
|
|
25
|
+
semanticSearch(vector: Float32Array, projectId: string, limit: number): Promise<SearchResult[]>;
|
|
26
|
+
}
|
|
27
|
+
interface EngineCommitStoreInput {
|
|
28
|
+
branchId: string;
|
|
29
|
+
agentId: string;
|
|
30
|
+
agentRole: AgentRole;
|
|
31
|
+
tool: string;
|
|
32
|
+
workflowType: WorkflowType;
|
|
33
|
+
message: string;
|
|
34
|
+
content: string;
|
|
35
|
+
summary: string;
|
|
36
|
+
commitType: CommitType;
|
|
37
|
+
gitCommitSha?: string;
|
|
38
|
+
ciRunId?: string;
|
|
39
|
+
pipelineName?: string;
|
|
40
|
+
threads?: {
|
|
41
|
+
open?: string[];
|
|
42
|
+
close?: Array<{
|
|
43
|
+
id: string;
|
|
44
|
+
note: string;
|
|
45
|
+
}>;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
interface EngineAgentInput {
|
|
49
|
+
id: string;
|
|
50
|
+
projectId: string;
|
|
51
|
+
role: AgentRole;
|
|
52
|
+
tool: string;
|
|
53
|
+
workflowType: WorkflowType;
|
|
54
|
+
}
|
|
55
|
+
export interface EngineCommitInput {
|
|
56
|
+
message: string;
|
|
57
|
+
content: string;
|
|
58
|
+
commitType?: CommitType;
|
|
59
|
+
gitCommitSha?: string;
|
|
60
|
+
ciRunId?: string;
|
|
61
|
+
pipelineName?: string;
|
|
62
|
+
threads?: {
|
|
63
|
+
open?: string[];
|
|
64
|
+
close?: Array<{
|
|
65
|
+
id: string;
|
|
66
|
+
note: string;
|
|
67
|
+
}>;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export interface EngineOptions {
|
|
71
|
+
summarizer?: RollingSummarizer;
|
|
72
|
+
embeddingService?: EmbeddingService;
|
|
73
|
+
}
|
|
74
|
+
export declare class ContextEngine {
|
|
75
|
+
private readonly store;
|
|
76
|
+
private readonly agentId;
|
|
77
|
+
private readonly agentRole;
|
|
78
|
+
private readonly tool;
|
|
79
|
+
private readonly workflowType;
|
|
80
|
+
private projectId;
|
|
81
|
+
private branchId;
|
|
82
|
+
private readonly summarizer;
|
|
83
|
+
private readonly embeddings;
|
|
84
|
+
constructor(store: EngineStore, agentId: string, agentRole: AgentRole, tool: string, workflowType: WorkflowType, options?: EngineOptions);
|
|
85
|
+
/**
|
|
86
|
+
* Bind the engine to a project + branch and register this agent.
|
|
87
|
+
* Must be called before commit() or context().
|
|
88
|
+
*/
|
|
89
|
+
init(projectId: string, branchId: string): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Persist a context commit. Summary is generated automatically via the
|
|
92
|
+
* RollingSummarizer (Week 1: string truncation; Week 2: Claude Haiku).
|
|
93
|
+
*/
|
|
94
|
+
commit(input: EngineCommitInput): Promise<Commit>;
|
|
95
|
+
/**
|
|
96
|
+
* Create a new branch from the current branch.
|
|
97
|
+
* Writes a `branch-init` commit on the new branch carrying the parent HEAD
|
|
98
|
+
* summary forward so the branch starts with full context.
|
|
99
|
+
*/
|
|
100
|
+
branch(gitBranch: string, name?: string): Promise<Branch>;
|
|
101
|
+
/**
|
|
102
|
+
* Merge a source branch into the current branch.
|
|
103
|
+
* Generates a rolling summary for the merge commit, carries open threads
|
|
104
|
+
* from source to target, and marks the source branch as merged.
|
|
105
|
+
*/
|
|
106
|
+
merge(sourceBranchId: string): Promise<Commit>;
|
|
107
|
+
/**
|
|
108
|
+
* Retrieve a SessionSnapshot for the current project+branch.
|
|
109
|
+
*
|
|
110
|
+
* scope='global' → full project snapshot (project summary + branch state)
|
|
111
|
+
* scope='branch' → same as global for now (branch-scoped view, Week 2)
|
|
112
|
+
* Other scopes → throws until implemented in later weeks
|
|
113
|
+
*/
|
|
114
|
+
context(scope: ContextScope): Promise<SessionSnapshot>;
|
|
115
|
+
/**
|
|
116
|
+
* Semantic search over commits in the current project.
|
|
117
|
+
* Requires an EmbeddingService to have been passed at construction time;
|
|
118
|
+
* returns an empty array if embeddings are unavailable.
|
|
119
|
+
*/
|
|
120
|
+
semanticSearch(query: string, projectId: string, limit?: number): Promise<SearchResult[]>;
|
|
121
|
+
private assertInitialized;
|
|
122
|
+
}
|
|
123
|
+
export {};
|
|
124
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// ContextEngine — pure business logic layer, no I/O.
|
|
2
|
+
// All persistence is delegated to the injected ContextStore.
|
|
3
|
+
//
|
|
4
|
+
// Usage:
|
|
5
|
+
// const engine = new ContextEngine(store, 'agent-1', 'dev', 'claude-code', 'interactive')
|
|
6
|
+
// await engine.init(projectId, branchId)
|
|
7
|
+
// await engine.commit({ message: '...', content: '...' })
|
|
8
|
+
// const snapshot = await engine.context('global')
|
|
9
|
+
import { RollingSummarizer } from './summarizer.js';
|
|
10
|
+
export class ContextEngine {
|
|
11
|
+
store;
|
|
12
|
+
agentId;
|
|
13
|
+
agentRole;
|
|
14
|
+
tool;
|
|
15
|
+
workflowType;
|
|
16
|
+
projectId = '';
|
|
17
|
+
branchId = '';
|
|
18
|
+
summarizer;
|
|
19
|
+
embeddings;
|
|
20
|
+
constructor(store, agentId, agentRole, tool, workflowType, options = {}) {
|
|
21
|
+
this.store = store;
|
|
22
|
+
this.agentId = agentId;
|
|
23
|
+
this.agentRole = agentRole;
|
|
24
|
+
this.tool = tool;
|
|
25
|
+
this.workflowType = workflowType;
|
|
26
|
+
this.summarizer = options.summarizer ?? new RollingSummarizer();
|
|
27
|
+
this.embeddings = options.embeddingService ?? null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Bind the engine to a project + branch and register this agent.
|
|
31
|
+
* Must be called before commit() or context().
|
|
32
|
+
*/
|
|
33
|
+
async init(projectId, branchId) {
|
|
34
|
+
this.projectId = projectId;
|
|
35
|
+
this.branchId = branchId;
|
|
36
|
+
await this.store.upsertAgent({
|
|
37
|
+
id: this.agentId,
|
|
38
|
+
projectId,
|
|
39
|
+
role: this.agentRole,
|
|
40
|
+
tool: this.tool,
|
|
41
|
+
workflowType: this.workflowType,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Persist a context commit. Summary is generated automatically via the
|
|
46
|
+
* RollingSummarizer (Week 1: string truncation; Week 2: Claude Haiku).
|
|
47
|
+
*/
|
|
48
|
+
async commit(input) {
|
|
49
|
+
this.assertInitialized();
|
|
50
|
+
// Fetch previous summary from branch HEAD (if any)
|
|
51
|
+
let previousSummary = '';
|
|
52
|
+
const branch = await this.store.getBranch(this.branchId);
|
|
53
|
+
if (branch?.headCommitId) {
|
|
54
|
+
const head = await this.store.getCommit(branch.headCommitId);
|
|
55
|
+
previousSummary = head?.summary ?? '';
|
|
56
|
+
}
|
|
57
|
+
const summary = await this.summarizer.summarize(input.content, previousSummary, 'branch');
|
|
58
|
+
const commit = await this.store.createCommit({
|
|
59
|
+
branchId: this.branchId,
|
|
60
|
+
agentId: this.agentId,
|
|
61
|
+
agentRole: this.agentRole,
|
|
62
|
+
tool: this.tool,
|
|
63
|
+
workflowType: this.workflowType,
|
|
64
|
+
message: input.message,
|
|
65
|
+
content: input.content,
|
|
66
|
+
summary,
|
|
67
|
+
commitType: input.commitType ?? 'manual',
|
|
68
|
+
gitCommitSha: input.gitCommitSha,
|
|
69
|
+
ciRunId: input.ciRunId,
|
|
70
|
+
pipelineName: input.pipelineName,
|
|
71
|
+
threads: input.threads,
|
|
72
|
+
});
|
|
73
|
+
// Generate and index embedding asynchronously — never block the commit.
|
|
74
|
+
if (this.embeddings) {
|
|
75
|
+
const text = `${input.message}\n${input.content}`;
|
|
76
|
+
this.embeddings.embed(text).then(vector => {
|
|
77
|
+
if (vector)
|
|
78
|
+
return this.store.indexEmbedding(commit.id, vector);
|
|
79
|
+
}).catch(() => { });
|
|
80
|
+
}
|
|
81
|
+
return commit;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create a new branch from the current branch.
|
|
85
|
+
* Writes a `branch-init` commit on the new branch carrying the parent HEAD
|
|
86
|
+
* summary forward so the branch starts with full context.
|
|
87
|
+
*/
|
|
88
|
+
async branch(gitBranch, name) {
|
|
89
|
+
this.assertInitialized();
|
|
90
|
+
// Carry parent HEAD summary into the new branch
|
|
91
|
+
const parentBranch = await this.store.getBranch(this.branchId);
|
|
92
|
+
let parentSummary = '';
|
|
93
|
+
if (parentBranch?.headCommitId) {
|
|
94
|
+
const head = await this.store.getCommit(parentBranch.headCommitId);
|
|
95
|
+
parentSummary = head?.summary ?? '';
|
|
96
|
+
}
|
|
97
|
+
const newBranch = await this.store.createBranch({
|
|
98
|
+
projectId: this.projectId,
|
|
99
|
+
name: name ?? gitBranch,
|
|
100
|
+
gitBranch,
|
|
101
|
+
parentBranchId: this.branchId,
|
|
102
|
+
});
|
|
103
|
+
// branch-init commit: carries parent summary, no rolling summarization needed
|
|
104
|
+
await this.store.createCommit({
|
|
105
|
+
branchId: newBranch.id,
|
|
106
|
+
agentId: this.agentId,
|
|
107
|
+
agentRole: this.agentRole,
|
|
108
|
+
tool: this.tool,
|
|
109
|
+
workflowType: this.workflowType,
|
|
110
|
+
message: `Branch ${gitBranch} created from ${parentBranch?.gitBranch ?? this.branchId}`,
|
|
111
|
+
content: parentSummary,
|
|
112
|
+
summary: parentSummary,
|
|
113
|
+
commitType: 'branch-init',
|
|
114
|
+
});
|
|
115
|
+
return newBranch;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Merge a source branch into the current branch.
|
|
119
|
+
* Generates a rolling summary for the merge commit, carries open threads
|
|
120
|
+
* from source to target, and marks the source branch as merged.
|
|
121
|
+
*/
|
|
122
|
+
async merge(sourceBranchId) {
|
|
123
|
+
this.assertInitialized();
|
|
124
|
+
// Source HEAD summary
|
|
125
|
+
const sourceBranch = await this.store.getBranch(sourceBranchId);
|
|
126
|
+
let sourceSummary = '';
|
|
127
|
+
if (sourceBranch?.headCommitId) {
|
|
128
|
+
const head = await this.store.getCommit(sourceBranch.headCommitId);
|
|
129
|
+
sourceSummary = head?.summary ?? '';
|
|
130
|
+
}
|
|
131
|
+
// Target (current branch) HEAD summary as the rolling base
|
|
132
|
+
const targetBranch = await this.store.getBranch(this.branchId);
|
|
133
|
+
let targetSummary = '';
|
|
134
|
+
if (targetBranch?.headCommitId) {
|
|
135
|
+
const head = await this.store.getCommit(targetBranch.headCommitId);
|
|
136
|
+
targetSummary = head?.summary ?? '';
|
|
137
|
+
}
|
|
138
|
+
const mergeContent = `Merged ${sourceBranch?.name ?? sourceBranchId}: ${sourceSummary}`;
|
|
139
|
+
const mergeSummary = await this.summarizer.summarize(mergeContent, targetSummary, 'branch');
|
|
140
|
+
return this.store.mergeBranch(sourceBranchId, this.branchId, mergeSummary);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Retrieve a SessionSnapshot for the current project+branch.
|
|
144
|
+
*
|
|
145
|
+
* scope='global' → full project snapshot (project summary + branch state)
|
|
146
|
+
* scope='branch' → same as global for now (branch-scoped view, Week 2)
|
|
147
|
+
* Other scopes → throws until implemented in later weeks
|
|
148
|
+
*/
|
|
149
|
+
async context(scope) {
|
|
150
|
+
this.assertInitialized();
|
|
151
|
+
if (scope === 'global' || scope === 'branch') {
|
|
152
|
+
return this.store.getSessionSnapshot(this.projectId, this.branchId);
|
|
153
|
+
}
|
|
154
|
+
throw new Error(`context scope '${scope}' is not yet implemented`);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Semantic search over commits in the current project.
|
|
158
|
+
* Requires an EmbeddingService to have been passed at construction time;
|
|
159
|
+
* returns an empty array if embeddings are unavailable.
|
|
160
|
+
*/
|
|
161
|
+
async semanticSearch(query, projectId, limit = 5) {
|
|
162
|
+
if (!this.embeddings)
|
|
163
|
+
return [];
|
|
164
|
+
const vector = await this.embeddings.embed(query);
|
|
165
|
+
if (!vector)
|
|
166
|
+
return [];
|
|
167
|
+
return this.store.semanticSearch(vector, projectId, limit);
|
|
168
|
+
}
|
|
169
|
+
assertInitialized() {
|
|
170
|
+
if (!this.projectId || !this.branchId) {
|
|
171
|
+
throw new Error('ContextEngine not initialized — call engine.init(projectId, branchId) first.');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEjE,qBAAa,iBAAiB;IAC5B,MAAM,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,MAAM;CA2E/D"}
|
package/dist/snapshot.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// SnapshotFormatter — converts a SessionSnapshot to one of the 3 output formats.
|
|
2
|
+
// Moved from store/local/index.ts (inline) to core so all consumers share the same output.
|
|
3
|
+
export class SnapshotFormatter {
|
|
4
|
+
format(snapshot, fmt) {
|
|
5
|
+
const { projectSummary, branchName, branchSummary, recentCommits, openThreads, activeClaims } = snapshot;
|
|
6
|
+
if (fmt === 'json') {
|
|
7
|
+
return JSON.stringify(snapshot, null, 2);
|
|
8
|
+
}
|
|
9
|
+
if (fmt === 'agents-md') {
|
|
10
|
+
const commits = recentCommits
|
|
11
|
+
.map((c) => `- [${c.createdAt.toISOString()}] "${c.message}" by ${c.agentRole} via ${c.tool} (${c.workflowType})`)
|
|
12
|
+
.join('\n');
|
|
13
|
+
const threads = openThreads
|
|
14
|
+
.map((t) => `- [ ] ${t.description} (opened ${t.createdAt.toLocaleDateString()}, ${t.workflowType ?? 'interactive'})`)
|
|
15
|
+
.join('\n');
|
|
16
|
+
const claims = activeClaims
|
|
17
|
+
.map((cl) => `- [${cl.status}] ${cl.task} by ${cl.agentId} (${cl.role})`)
|
|
18
|
+
.join('\n');
|
|
19
|
+
return [
|
|
20
|
+
`## Project State`,
|
|
21
|
+
projectSummary || '(no summary yet)',
|
|
22
|
+
``,
|
|
23
|
+
`## Current Branch: ${branchName}`,
|
|
24
|
+
branchSummary || '(no branch summary yet)',
|
|
25
|
+
``,
|
|
26
|
+
`## Recent Activity`,
|
|
27
|
+
commits || '(no commits yet)',
|
|
28
|
+
``,
|
|
29
|
+
`## Open Threads`,
|
|
30
|
+
threads || '(none)',
|
|
31
|
+
``,
|
|
32
|
+
`## Active Claims`,
|
|
33
|
+
claims || '(none)',
|
|
34
|
+
].join('\n');
|
|
35
|
+
}
|
|
36
|
+
// text (default)
|
|
37
|
+
const commits = recentCommits
|
|
38
|
+
.map((c) => `[${c.createdAt.toISOString()}] "${c.message}" by ${c.agentRole} via ${c.tool} (${c.workflowType})`)
|
|
39
|
+
.join('\n');
|
|
40
|
+
const threads = openThreads
|
|
41
|
+
.map((t) => `[ ] ${t.description} (opened ${t.createdAt.toLocaleDateString()}, ${t.workflowType ?? 'interactive'})`)
|
|
42
|
+
.join('\n');
|
|
43
|
+
const claims = activeClaims
|
|
44
|
+
.map((cl) => `[${cl.status}] ${cl.task} by ${cl.agentId} (${cl.role})`)
|
|
45
|
+
.join('\n');
|
|
46
|
+
return [
|
|
47
|
+
`=== PROJECT STATE ===`,
|
|
48
|
+
projectSummary || '(no summary yet)',
|
|
49
|
+
``,
|
|
50
|
+
`=== CURRENT BRANCH: ${branchName} ===`,
|
|
51
|
+
branchSummary || '(no branch summary yet)',
|
|
52
|
+
``,
|
|
53
|
+
`=== LAST 3 COMMITS ===`,
|
|
54
|
+
commits || '(none)',
|
|
55
|
+
``,
|
|
56
|
+
`=== OPEN THREADS ===`,
|
|
57
|
+
threads || '(none)',
|
|
58
|
+
``,
|
|
59
|
+
`=== ACTIVE CLAIMS ===`,
|
|
60
|
+
claims || '(none)',
|
|
61
|
+
].join('\n');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
export interface SummarizerOptions {
|
|
3
|
+
/** Max characters for project-level summaries (~2000 tokens). */
|
|
4
|
+
maxProjectChars?: number;
|
|
5
|
+
/** Max characters for branch-level summaries (~500 tokens). */
|
|
6
|
+
maxBranchChars?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Inject a pre-built Anthropic client (useful for tests).
|
|
9
|
+
* If omitted, one is created from ANTHROPIC_API_KEY.
|
|
10
|
+
* If ANTHROPIC_API_KEY is also absent, falls back to string truncation.
|
|
11
|
+
*/
|
|
12
|
+
client?: Anthropic;
|
|
13
|
+
}
|
|
14
|
+
export declare class RollingSummarizer {
|
|
15
|
+
private readonly maxProjectChars;
|
|
16
|
+
private readonly maxBranchChars;
|
|
17
|
+
private readonly client;
|
|
18
|
+
constructor(options?: SummarizerOptions);
|
|
19
|
+
/**
|
|
20
|
+
* Roll `content` into `previousSummary` and return a new summary that fits
|
|
21
|
+
* within the budget for the given scope.
|
|
22
|
+
*
|
|
23
|
+
* Week 2: uses Claude Haiku for intelligent compression.
|
|
24
|
+
* Fallback: dumb truncation (newest content appended, trimmed from the start
|
|
25
|
+
* so the most-recent work is always present).
|
|
26
|
+
*
|
|
27
|
+
* Never throws — summarizer failures are silently swallowed.
|
|
28
|
+
*/
|
|
29
|
+
summarize(content: string, previousSummary: string, budget: 'project' | 'branch'): Promise<string>;
|
|
30
|
+
private _claudeSummarize;
|
|
31
|
+
private _truncateSummarize;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=summarizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summarizer.d.ts","sourceRoot":"","sources":["../src/summarizer.ts"],"names":[],"mappings":"AAIA,OAAO,SAAS,MAAM,mBAAmB,CAAA;AAEzC,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;gBAE7B,OAAO,GAAE,iBAAsB;IAa3C;;;;;;;;;OASG;IACG,SAAS,CACb,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,SAAS,GAAG,QAAQ,GAC3B,OAAO,CAAC,MAAM,CAAC;YAgBJ,gBAAgB;IAmC9B,OAAO,CAAC,kBAAkB;CAU3B"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// RollingSummarizer — Week 2: Claude Haiku with graceful string-truncation fallback.
|
|
2
|
+
// If the API key is absent or the API call fails, falls back to string truncation.
|
|
3
|
+
// The interface is stable; callers never know which implementation is running.
|
|
4
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
5
|
+
export class RollingSummarizer {
|
|
6
|
+
maxProjectChars;
|
|
7
|
+
maxBranchChars;
|
|
8
|
+
client;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.maxProjectChars = options.maxProjectChars ?? 8000;
|
|
11
|
+
this.maxBranchChars = options.maxBranchChars ?? 2000;
|
|
12
|
+
if (options.client !== undefined) {
|
|
13
|
+
this.client = options.client;
|
|
14
|
+
}
|
|
15
|
+
else if (process.env['ANTHROPIC_API_KEY']) {
|
|
16
|
+
this.client = new Anthropic();
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
this.client = null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Roll `content` into `previousSummary` and return a new summary that fits
|
|
24
|
+
* within the budget for the given scope.
|
|
25
|
+
*
|
|
26
|
+
* Week 2: uses Claude Haiku for intelligent compression.
|
|
27
|
+
* Fallback: dumb truncation (newest content appended, trimmed from the start
|
|
28
|
+
* so the most-recent work is always present).
|
|
29
|
+
*
|
|
30
|
+
* Never throws — summarizer failures are silently swallowed.
|
|
31
|
+
*/
|
|
32
|
+
async summarize(content, previousSummary, budget) {
|
|
33
|
+
const max = budget === 'project' ? this.maxProjectChars : this.maxBranchChars;
|
|
34
|
+
if (this.client !== null) {
|
|
35
|
+
try {
|
|
36
|
+
return await this._claudeSummarize(content, previousSummary, max);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Graceful fallback — never propagate summarizer failure to the caller.
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return this._truncateSummarize(content, previousSummary, max);
|
|
43
|
+
}
|
|
44
|
+
// ─── Private ────────────────────────────────────────────────────────────────
|
|
45
|
+
async _claudeSummarize(content, previousSummary, maxChars) {
|
|
46
|
+
const userContent = previousSummary
|
|
47
|
+
? `Previous summary:\n${previousSummary}\n\nNew content to integrate:\n${content}`
|
|
48
|
+
: `Content to summarize:\n${content}`;
|
|
49
|
+
const response = await this.client.messages.create({
|
|
50
|
+
model: 'claude-haiku-4-5',
|
|
51
|
+
max_tokens: 1024,
|
|
52
|
+
system: 'You are a context summarizer for an AI coding agent. ' +
|
|
53
|
+
'Return only the summary text with no preamble or explanation.',
|
|
54
|
+
messages: [
|
|
55
|
+
{
|
|
56
|
+
role: 'user',
|
|
57
|
+
content: userContent +
|
|
58
|
+
`\n\nCreate a concise rolling summary (max ${maxChars} characters) ` +
|
|
59
|
+
'that preserves the most important recent work and decisions. ' +
|
|
60
|
+
'Return only the summary text.',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
const text = response.content
|
|
65
|
+
.filter((b) => b.type === 'text')
|
|
66
|
+
.map(b => b.text)
|
|
67
|
+
.join('');
|
|
68
|
+
return text.slice(0, maxChars);
|
|
69
|
+
}
|
|
70
|
+
_truncateSummarize(content, previousSummary, max) {
|
|
71
|
+
const combined = previousSummary ? `${previousSummary}\n\n${content}` : content;
|
|
72
|
+
if (combined.length <= max)
|
|
73
|
+
return combined;
|
|
74
|
+
// Keep the tail so recent work is never lost.
|
|
75
|
+
return combined.slice(combined.length - max);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=summarizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summarizer.js","sourceRoot":"","sources":["../src/summarizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summarizer.test.d.ts","sourceRoot":"","sources":["../src/summarizer.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Week 2 summarizer tests.
|
|
2
|
+
// All API calls are mocked — no network required.
|
|
3
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
4
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
5
|
+
import { RollingSummarizer } from './summarizer.js';
|
|
6
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
7
|
+
function makeClient(responseText) {
|
|
8
|
+
const client = new Anthropic({ apiKey: 'test-key' });
|
|
9
|
+
vi.spyOn(client.messages, 'create').mockResolvedValue({
|
|
10
|
+
id: 'msg_test',
|
|
11
|
+
type: 'message',
|
|
12
|
+
role: 'assistant',
|
|
13
|
+
content: [{ type: 'text', text: responseText }],
|
|
14
|
+
model: 'claude-haiku-4-5',
|
|
15
|
+
stop_reason: 'end_turn',
|
|
16
|
+
stop_sequence: null,
|
|
17
|
+
usage: { input_tokens: 10, output_tokens: 20 },
|
|
18
|
+
});
|
|
19
|
+
return client;
|
|
20
|
+
}
|
|
21
|
+
function makeFailingClient() {
|
|
22
|
+
const client = new Anthropic({ apiKey: 'test-key' });
|
|
23
|
+
vi.spyOn(client.messages, 'create').mockRejectedValue(new Error('Simulated API failure'));
|
|
24
|
+
return client;
|
|
25
|
+
}
|
|
26
|
+
// ─── Tests ───────────────────────────────────────────────────────────────────
|
|
27
|
+
describe('RollingSummarizer', () => {
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
vi.restoreAllMocks();
|
|
30
|
+
});
|
|
31
|
+
it('returns Claude summary when API succeeds', async () => {
|
|
32
|
+
const claudeReply = 'Concise summary from Claude Haiku.';
|
|
33
|
+
const summarizer = new RollingSummarizer({ client: makeClient(claudeReply) });
|
|
34
|
+
const result = await summarizer.summarize('some content', '', 'branch');
|
|
35
|
+
expect(result).toBe(claudeReply);
|
|
36
|
+
});
|
|
37
|
+
it('passes previous summary and new content to Claude', async () => {
|
|
38
|
+
const client = makeClient('merged summary');
|
|
39
|
+
const summarizer = new RollingSummarizer({ client });
|
|
40
|
+
await summarizer.summarize('new work', 'old summary', 'branch');
|
|
41
|
+
const callArg = client.messages.create.mock
|
|
42
|
+
.calls[0][0];
|
|
43
|
+
const userContent = callArg.messages[0].content;
|
|
44
|
+
expect(userContent).toContain('old summary');
|
|
45
|
+
expect(userContent).toContain('new work');
|
|
46
|
+
});
|
|
47
|
+
it('falls back to string truncation when API fails', async () => {
|
|
48
|
+
const summarizer = new RollingSummarizer({ client: makeFailingClient() });
|
|
49
|
+
const result = await summarizer.summarize('beta', 'alpha', 'branch');
|
|
50
|
+
// Fallback: concatenate and keep; both fit in 2000 chars
|
|
51
|
+
expect(result).toContain('alpha');
|
|
52
|
+
expect(result).toContain('beta');
|
|
53
|
+
});
|
|
54
|
+
it('never throws when API fails', async () => {
|
|
55
|
+
const summarizer = new RollingSummarizer({ client: makeFailingClient() });
|
|
56
|
+
await expect(summarizer.summarize('content', '', 'branch')).resolves.toBeDefined();
|
|
57
|
+
});
|
|
58
|
+
it('falls back to string truncation when no client is injected and ANTHROPIC_API_KEY is absent', async () => {
|
|
59
|
+
const savedKey = process.env['ANTHROPIC_API_KEY'];
|
|
60
|
+
delete process.env['ANTHROPIC_API_KEY'];
|
|
61
|
+
try {
|
|
62
|
+
const summarizer = new RollingSummarizer();
|
|
63
|
+
const result = await summarizer.summarize('beta content', 'alpha content', 'branch');
|
|
64
|
+
expect(result).toContain('alpha content');
|
|
65
|
+
expect(result).toContain('beta content');
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
if (savedKey !== undefined)
|
|
69
|
+
process.env['ANTHROPIC_API_KEY'] = savedKey;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
it('truncates from the start (keeps newest) when fallback overflows budget', async () => {
|
|
73
|
+
const savedKey = process.env['ANTHROPIC_API_KEY'];
|
|
74
|
+
delete process.env['ANTHROPIC_API_KEY'];
|
|
75
|
+
try {
|
|
76
|
+
const summarizer = new RollingSummarizer({ maxBranchChars: 20 });
|
|
77
|
+
const result = await summarizer.summarize('NEWEST', 'A'.repeat(30), 'branch');
|
|
78
|
+
// Budget is 20 chars; tail of the combined string should end with NEWEST
|
|
79
|
+
expect(result).toHaveLength(20);
|
|
80
|
+
expect(result.endsWith('NEWEST')).toBe(true);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
if (savedKey !== undefined)
|
|
84
|
+
process.env['ANTHROPIC_API_KEY'] = savedKey;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
it('respects maxChars for Claude response (truncates to budget)', async () => {
|
|
88
|
+
const longReply = 'X'.repeat(5000);
|
|
89
|
+
const summarizer = new RollingSummarizer({
|
|
90
|
+
client: makeClient(longReply),
|
|
91
|
+
maxBranchChars: 100,
|
|
92
|
+
});
|
|
93
|
+
const result = await summarizer.summarize('content', '', 'branch');
|
|
94
|
+
expect(result).toHaveLength(100);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=summarizer.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summarizer.test.js","sourceRoot":"","sources":["../src/summarizer.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Thread } from './types.js';
|
|
2
|
+
export interface ThreadReader {
|
|
3
|
+
listOpenThreads(projectId: string): Promise<Thread[]>;
|
|
4
|
+
listOpenThreadsByBranch(branchId: string): Promise<Thread[]>;
|
|
5
|
+
}
|
|
6
|
+
export declare class ThreadManager {
|
|
7
|
+
private readonly store;
|
|
8
|
+
constructor(store: ThreadReader);
|
|
9
|
+
/** All open threads for a project, across all branches. */
|
|
10
|
+
openForProject(projectId: string): Promise<Thread[]>;
|
|
11
|
+
/** Open threads scoped to a single branch. */
|
|
12
|
+
openForBranch(branchId: string): Promise<Thread[]>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=threads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../src/threads.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACrD,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;CAC7D;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,YAAY;IAEhD,2DAA2D;IAC3D,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAIpD,8CAA8C;IAC9C,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAGnD"}
|
package/dist/threads.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// ThreadManager — read-side helper for the open-thread immune-to-compression guarantee.
|
|
2
|
+
//
|
|
3
|
+
// Key invariant: open threads are stored in the `threads` table and NEVER
|
|
4
|
+
// passed to the summarizer. This file enforces that boundary by providing
|
|
5
|
+
// the only sanctioned way to query open threads.
|
|
6
|
+
//
|
|
7
|
+
// Write-side (opening / closing threads) happens via CommitInput.threads
|
|
8
|
+
// inside store.createCommit(), which is the right transactional boundary.
|
|
9
|
+
export class ThreadManager {
|
|
10
|
+
store;
|
|
11
|
+
constructor(store) {
|
|
12
|
+
this.store = store;
|
|
13
|
+
}
|
|
14
|
+
/** All open threads for a project, across all branches. */
|
|
15
|
+
openForProject(projectId) {
|
|
16
|
+
return this.store.listOpenThreads(projectId);
|
|
17
|
+
}
|
|
18
|
+
/** Open threads scoped to a single branch. */
|
|
19
|
+
openForBranch(branchId) {
|
|
20
|
+
return this.store.listOpenThreadsByBranch(branchId);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=threads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threads.js","sourceRoot":"","sources":["../src/threads.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,iDAAiD;AACjD,EAAE;AACF,yEAAyE;AACzE,0EAA0E;AAS1E,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,KAAmB;QAAnB,UAAK,GAAL,KAAK,CAAc;IAAG,CAAC;IAEpD,2DAA2D;IAC3D,cAAc,CAAC,SAAiB;QAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,SAAS,CAAC,CAAA;IAC9C,CAAC;IAED,8CAA8C;IAC9C,aAAa,CAAC,QAAgB;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAA;IACrD,CAAC;CACF"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
export type AgentRole = 'orchestrator' | 'dev' | 'test' | 'review' | 'background' | 'ci' | 'solo';
|
|
2
|
+
export type WorkflowType = 'interactive' | 'ralph-loop' | 'ci' | 'background' | 'custom';
|
|
3
|
+
export type CommitType = 'manual' | 'auto' | 'merge' | 'branch-init';
|
|
4
|
+
export type BranchStatus = 'active' | 'merged' | 'abandoned';
|
|
5
|
+
export type ClaimStatus = 'proposed' | 'active' | 'released';
|
|
6
|
+
export type SnapshotFormat = 'agents-md' | 'json' | 'text';
|
|
7
|
+
export type ContextScope = 'global' | 'branch' | 'search' | 'commit' | 'raw';
|
|
8
|
+
export interface Project {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
githubUrl?: string;
|
|
13
|
+
createdAt: Date;
|
|
14
|
+
}
|
|
15
|
+
export interface Branch {
|
|
16
|
+
id: string;
|
|
17
|
+
projectId: string;
|
|
18
|
+
name: string;
|
|
19
|
+
gitBranch: string;
|
|
20
|
+
githubPrUrl?: string;
|
|
21
|
+
parentBranchId?: string;
|
|
22
|
+
headCommitId?: string;
|
|
23
|
+
status: BranchStatus;
|
|
24
|
+
createdAt: Date;
|
|
25
|
+
mergedAt?: Date;
|
|
26
|
+
}
|
|
27
|
+
export interface Commit {
|
|
28
|
+
id: string;
|
|
29
|
+
branchId: string;
|
|
30
|
+
parentId?: string;
|
|
31
|
+
mergeSourceBranchId?: string;
|
|
32
|
+
agentId: string;
|
|
33
|
+
agentRole: AgentRole;
|
|
34
|
+
tool: string;
|
|
35
|
+
workflowType: WorkflowType;
|
|
36
|
+
loopIteration?: number;
|
|
37
|
+
ciRunId?: string;
|
|
38
|
+
pipelineName?: string;
|
|
39
|
+
message: string;
|
|
40
|
+
content: string;
|
|
41
|
+
summary: string;
|
|
42
|
+
commitType: CommitType;
|
|
43
|
+
gitCommitSha?: string;
|
|
44
|
+
createdAt: Date;
|
|
45
|
+
}
|
|
46
|
+
export interface Thread {
|
|
47
|
+
id: string;
|
|
48
|
+
projectId: string;
|
|
49
|
+
branchId: string;
|
|
50
|
+
description: string;
|
|
51
|
+
status: 'open' | 'closed';
|
|
52
|
+
workflowType?: WorkflowType;
|
|
53
|
+
openedInCommit: string;
|
|
54
|
+
closedInCommit?: string;
|
|
55
|
+
closedNote?: string;
|
|
56
|
+
createdAt: Date;
|
|
57
|
+
}
|
|
58
|
+
export interface Agent {
|
|
59
|
+
id: string;
|
|
60
|
+
projectId: string;
|
|
61
|
+
role: AgentRole;
|
|
62
|
+
tool: string;
|
|
63
|
+
workflowType: WorkflowType;
|
|
64
|
+
displayName?: string;
|
|
65
|
+
totalCommits: number;
|
|
66
|
+
lastSeen: Date;
|
|
67
|
+
createdAt: Date;
|
|
68
|
+
}
|
|
69
|
+
export interface Claim {
|
|
70
|
+
id: string;
|
|
71
|
+
projectId: string;
|
|
72
|
+
branchId: string;
|
|
73
|
+
task: string;
|
|
74
|
+
agentId: string;
|
|
75
|
+
role: AgentRole;
|
|
76
|
+
claimedAt: Date;
|
|
77
|
+
status: ClaimStatus;
|
|
78
|
+
ttl: number;
|
|
79
|
+
releasedAt?: Date;
|
|
80
|
+
}
|
|
81
|
+
export interface ProjectInput {
|
|
82
|
+
id?: string;
|
|
83
|
+
name: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
githubUrl?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface BranchInput {
|
|
88
|
+
id?: string;
|
|
89
|
+
projectId: string;
|
|
90
|
+
name: string;
|
|
91
|
+
gitBranch: string;
|
|
92
|
+
parentBranchId?: string;
|
|
93
|
+
githubPrUrl?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface CommitInput {
|
|
96
|
+
id?: string;
|
|
97
|
+
branchId: string;
|
|
98
|
+
parentId?: string;
|
|
99
|
+
agentId: string;
|
|
100
|
+
agentRole: AgentRole;
|
|
101
|
+
tool: string;
|
|
102
|
+
workflowType: WorkflowType;
|
|
103
|
+
loopIteration?: number;
|
|
104
|
+
ciRunId?: string;
|
|
105
|
+
pipelineName?: string;
|
|
106
|
+
message: string;
|
|
107
|
+
content: string;
|
|
108
|
+
summary: string;
|
|
109
|
+
commitType: CommitType;
|
|
110
|
+
gitCommitSha?: string;
|
|
111
|
+
threads?: {
|
|
112
|
+
open?: string[];
|
|
113
|
+
close?: Array<{
|
|
114
|
+
id: string;
|
|
115
|
+
note: string;
|
|
116
|
+
}>;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
export interface AgentInput {
|
|
120
|
+
id: string;
|
|
121
|
+
projectId: string;
|
|
122
|
+
role: AgentRole;
|
|
123
|
+
tool: string;
|
|
124
|
+
workflowType: WorkflowType;
|
|
125
|
+
displayName?: string;
|
|
126
|
+
}
|
|
127
|
+
export interface ClaimInput {
|
|
128
|
+
task: string;
|
|
129
|
+
agentId: string;
|
|
130
|
+
role: AgentRole;
|
|
131
|
+
status?: ClaimStatus;
|
|
132
|
+
ttl?: number;
|
|
133
|
+
}
|
|
134
|
+
export interface SessionSnapshot {
|
|
135
|
+
projectSummary: string;
|
|
136
|
+
branchName: string;
|
|
137
|
+
branchSummary: string;
|
|
138
|
+
recentCommits: Commit[];
|
|
139
|
+
openThreads: Thread[];
|
|
140
|
+
activeClaims: Claim[];
|
|
141
|
+
}
|
|
142
|
+
export interface SearchResult {
|
|
143
|
+
commit: Commit;
|
|
144
|
+
score: number;
|
|
145
|
+
matchType: 'semantic' | 'fulltext';
|
|
146
|
+
}
|
|
147
|
+
export interface ContextGitConfig {
|
|
148
|
+
project: string;
|
|
149
|
+
projectId: string;
|
|
150
|
+
store: 'local' | string;
|
|
151
|
+
remote?: string;
|
|
152
|
+
agentRole: AgentRole;
|
|
153
|
+
workflowType: WorkflowType;
|
|
154
|
+
autoSnapshot: boolean;
|
|
155
|
+
snapshotInterval: number;
|
|
156
|
+
embeddingModel: 'local' | 'openai';
|
|
157
|
+
apiKey?: string;
|
|
158
|
+
}
|
|
159
|
+
export interface Pagination {
|
|
160
|
+
limit: number;
|
|
161
|
+
offset: number;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,+CAA+C;AAC/C,kBAAkB;AAClB,+CAA+C"}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@contextgit/core",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": ["dist"],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"typecheck": "tsc --noEmit"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@anthropic-ai/sdk": "^0.40.1",
|
|
21
|
+
"@xenova/transformers": "^2.17.2",
|
|
22
|
+
"nanoid": "^5.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^20.0.0",
|
|
26
|
+
"typescript": "^5.4.0",
|
|
27
|
+
"vitest": "^1.6.0"
|
|
28
|
+
}
|
|
29
|
+
}
|