praana 0.5.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 +124 -0
- package/bin/praana.js +17 -0
- package/bin/pran.js +17 -0
- package/dist/app-banner.d.ts +11 -0
- package/dist/app-banner.js +161 -0
- package/dist/app-controller.d.ts +44 -0
- package/dist/app-controller.js +143 -0
- package/dist/app-identity.d.ts +18 -0
- package/dist/app-identity.js +52 -0
- package/dist/auto-compact.d.ts +16 -0
- package/dist/auto-compact.js +101 -0
- package/dist/cli-args.d.ts +14 -0
- package/dist/cli-args.js +69 -0
- package/dist/compile-classic.d.ts +21 -0
- package/dist/compile-classic.js +106 -0
- package/dist/compiler.d.ts +75 -0
- package/dist/compiler.js +406 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +433 -0
- package/dist/context-engine/activity-log.d.ts +9 -0
- package/dist/context-engine/activity-log.js +109 -0
- package/dist/context-engine/artifact-store.d.ts +32 -0
- package/dist/context-engine/artifact-store.js +272 -0
- package/dist/context-engine/bm25.d.ts +3 -0
- package/dist/context-engine/bm25.js +32 -0
- package/dist/context-engine/checkpoint.d.ts +34 -0
- package/dist/context-engine/checkpoint.js +430 -0
- package/dist/context-engine/classify.d.ts +3 -0
- package/dist/context-engine/classify.js +60 -0
- package/dist/context-engine/db.d.ts +73 -0
- package/dist/context-engine/db.js +505 -0
- package/dist/context-engine/distiller.d.ts +30 -0
- package/dist/context-engine/distiller.js +67 -0
- package/dist/context-engine/engine-compiler.d.ts +23 -0
- package/dist/context-engine/engine-compiler.js +297 -0
- package/dist/context-engine/error-tracker.d.ts +21 -0
- package/dist/context-engine/error-tracker.js +74 -0
- package/dist/context-engine/event-lineage.d.ts +26 -0
- package/dist/context-engine/event-lineage.js +120 -0
- package/dist/context-engine/extraction.d.ts +26 -0
- package/dist/context-engine/extraction.js +83 -0
- package/dist/context-engine/index.d.ts +82 -0
- package/dist/context-engine/index.js +238 -0
- package/dist/context-engine/scoring.d.ts +13 -0
- package/dist/context-engine/scoring.js +47 -0
- package/dist/context-engine/state-snapshot.d.ts +8 -0
- package/dist/context-engine/state-snapshot.js +50 -0
- package/dist/context-engine/summarize.d.ts +6 -0
- package/dist/context-engine/summarize.js +32 -0
- package/dist/context-engine/telemetry.d.ts +25 -0
- package/dist/context-engine/telemetry.js +64 -0
- package/dist/context-engine/turn-digest.d.ts +50 -0
- package/dist/context-engine/turn-digest.js +250 -0
- package/dist/context-engine/turn-ledger.d.ts +18 -0
- package/dist/context-engine/turn-ledger.js +184 -0
- package/dist/context-engine/turn-recorder.d.ts +24 -0
- package/dist/context-engine/turn-recorder.js +88 -0
- package/dist/context-engine/types.d.ts +201 -0
- package/dist/context-engine/types.js +4 -0
- package/dist/context-pressure.d.ts +19 -0
- package/dist/context-pressure.js +36 -0
- package/dist/distillers/generic.d.ts +14 -0
- package/dist/distillers/generic.js +93 -0
- package/dist/distillers/git-diff.d.ts +8 -0
- package/dist/distillers/git-diff.js +119 -0
- package/dist/distillers/index.d.ts +2 -0
- package/dist/distillers/index.js +16 -0
- package/dist/distillers/npm-test.d.ts +8 -0
- package/dist/distillers/npm-test.js +50 -0
- package/dist/distillers/rg-results.d.ts +8 -0
- package/dist/distillers/rg-results.js +28 -0
- package/dist/distillers/tsc-errors.d.ts +8 -0
- package/dist/distillers/tsc-errors.js +52 -0
- package/dist/event-log.d.ts +56 -0
- package/dist/event-log.js +214 -0
- package/dist/llm.d.ts +29 -0
- package/dist/llm.js +155 -0
- package/dist/logger.d.ts +94 -0
- package/dist/logger.js +287 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +54 -0
- package/dist/memory/confidence.d.ts +7 -0
- package/dist/memory/confidence.js +37 -0
- package/dist/memory/consolidation.d.ts +26 -0
- package/dist/memory/consolidation.js +166 -0
- package/dist/memory/db.d.ts +40 -0
- package/dist/memory/db.js +283 -0
- package/dist/memory/dedup.d.ts +6 -0
- package/dist/memory/dedup.js +50 -0
- package/dist/memory/embedder-factory.d.ts +3 -0
- package/dist/memory/embedder-factory.js +81 -0
- package/dist/memory/embeddings.d.ts +15 -0
- package/dist/memory/embeddings.js +67 -0
- package/dist/memory/index.d.ts +9 -0
- package/dist/memory/index.js +11 -0
- package/dist/memory/ollama-summarizer.d.ts +19 -0
- package/dist/memory/ollama-summarizer.js +72 -0
- package/dist/memory/openai-summarizer.d.ts +21 -0
- package/dist/memory/openai-summarizer.js +51 -0
- package/dist/memory/store.d.ts +61 -0
- package/dist/memory/store.js +502 -0
- package/dist/memory/summarizer-factory.d.ts +3 -0
- package/dist/memory/summarizer-factory.js +69 -0
- package/dist/memory/summarizer.d.ts +4 -0
- package/dist/memory/summarizer.js +112 -0
- package/dist/memory/types.d.ts +87 -0
- package/dist/memory/types.js +17 -0
- package/dist/model-context.d.ts +15 -0
- package/dist/model-context.js +212 -0
- package/dist/project-detector.d.ts +37 -0
- package/dist/project-detector.js +604 -0
- package/dist/render.d.ts +15 -0
- package/dist/render.js +46 -0
- package/dist/session.d.ts +118 -0
- package/dist/session.js +809 -0
- package/dist/skills/index.d.ts +69 -0
- package/dist/skills/index.js +885 -0
- package/dist/skills/types.d.ts +93 -0
- package/dist/skills/types.js +8 -0
- package/dist/slash-commands.d.ts +14 -0
- package/dist/slash-commands.js +301 -0
- package/dist/state-graph.d.ts +38 -0
- package/dist/state-graph.js +255 -0
- package/dist/status-bar.d.ts +54 -0
- package/dist/status-bar.js +184 -0
- package/dist/thinking-display.d.ts +21 -0
- package/dist/thinking-display.js +37 -0
- package/dist/tool-summary.d.ts +4 -0
- package/dist/tool-summary.js +67 -0
- package/dist/tools/index.d.ts +925 -0
- package/dist/tools/index.js +86 -0
- package/dist/tools/knowledge.d.ts +140 -0
- package/dist/tools/knowledge.js +260 -0
- package/dist/tools/memory.d.ts +39 -0
- package/dist/tools/memory.js +300 -0
- package/dist/tools/search-code.d.ts +134 -0
- package/dist/tools/search-code.js +390 -0
- package/dist/tools/system.d.ts +16 -0
- package/dist/tools/system.js +499 -0
- package/dist/tools/tool-def.d.ts +6 -0
- package/dist/tools/tool-def.js +3 -0
- package/dist/turn-control.d.ts +51 -0
- package/dist/turn-control.js +210 -0
- package/dist/turn.d.ts +20 -0
- package/dist/turn.js +624 -0
- package/dist/types.d.ts +233 -0
- package/dist/types.js +4 -0
- package/dist/ui/readline-ui.d.ts +2 -0
- package/dist/ui/readline-ui.js +176 -0
- package/dist/ui/tui/app.d.ts +13 -0
- package/dist/ui/tui/app.js +270 -0
- package/dist/ui/tui/busy-indicator.d.ts +2 -0
- package/dist/ui/tui/busy-indicator.js +13 -0
- package/dist/ui/tui/components/gutter-rule.d.ts +5 -0
- package/dist/ui/tui/components/gutter-rule.js +9 -0
- package/dist/ui/tui/components/inline-tool-row.d.ts +10 -0
- package/dist/ui/tui/components/inline-tool-row.js +8 -0
- package/dist/ui/tui/components/prompt-input.d.ts +20 -0
- package/dist/ui/tui/components/prompt-input.js +120 -0
- package/dist/ui/tui/components/system-line.d.ts +5 -0
- package/dist/ui/tui/components/system-line.js +6 -0
- package/dist/ui/tui/components/thinking-block.d.ts +11 -0
- package/dist/ui/tui/components/thinking-block.js +31 -0
- package/dist/ui/tui/components/toast-line.d.ts +4 -0
- package/dist/ui/tui/components/toast-line.js +8 -0
- package/dist/ui/tui/components/tool-result-line.d.ts +5 -0
- package/dist/ui/tui/components/tool-result-line.js +6 -0
- package/dist/ui/tui/components/turn-footer.d.ts +5 -0
- package/dist/ui/tui/components/turn-footer.js +7 -0
- package/dist/ui/tui/components/user-block.d.ts +6 -0
- package/dist/ui/tui/components/user-block.js +6 -0
- package/dist/ui/tui/logo-banner.d.ts +5 -0
- package/dist/ui/tui/logo-banner.js +8 -0
- package/dist/ui/tui/markdown-render.d.ts +16 -0
- package/dist/ui/tui/markdown-render.js +218 -0
- package/dist/ui/tui/palette.d.ts +12 -0
- package/dist/ui/tui/palette.js +13 -0
- package/dist/ui/tui/reasoning-summary.d.ts +12 -0
- package/dist/ui/tui/reasoning-summary.js +27 -0
- package/dist/ui/tui/reducer.d.ts +92 -0
- package/dist/ui/tui/reducer.js +260 -0
- package/dist/ui/tui/run.d.ts +3 -0
- package/dist/ui/tui/run.js +40 -0
- package/dist/ui/tui/sink.d.ts +4 -0
- package/dist/ui/tui/sink.js +89 -0
- package/dist/ui/tui/status-bar-view.d.ts +5 -0
- package/dist/ui/tui/status-bar-view.js +44 -0
- package/dist/ui/tui/terminal-height.d.ts +12 -0
- package/dist/ui/tui/terminal-height.js +20 -0
- package/dist/ui/tui/terminal-width.d.ts +2 -0
- package/dist/ui/tui/terminal-width.js +5 -0
- package/dist/ui/tui/tool-display.d.ts +23 -0
- package/dist/ui/tui/tool-display.js +217 -0
- package/dist/ui/tui/transcript-line.d.ts +12 -0
- package/dist/ui/tui/transcript-line.js +43 -0
- package/dist/ui/tui/transcript-replay.d.ts +12 -0
- package/dist/ui/tui/transcript-replay.js +117 -0
- package/dist/ui-events.d.ts +39 -0
- package/dist/ui-events.js +33 -0
- package/dist/ui.d.ts +77 -0
- package/dist/ui.js +179 -0
- package/package.json +73 -0
- package/praana.config.example.toml +231 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
export type ContentType = "code" | "diff" | "log" | "json" | "test_output" | "build_output" | "search_results" | "error" | "prose" | "other";
|
|
2
|
+
export interface ContextArtifact {
|
|
3
|
+
id: string;
|
|
4
|
+
sha256: string;
|
|
5
|
+
sessionId: string;
|
|
6
|
+
sourceTool: string;
|
|
7
|
+
command?: string;
|
|
8
|
+
createdTurn: number;
|
|
9
|
+
rawTokens: number;
|
|
10
|
+
rawText: string;
|
|
11
|
+
summary: string;
|
|
12
|
+
contentType: ContentType;
|
|
13
|
+
lastAccessedTurn: number;
|
|
14
|
+
accessCount: number;
|
|
15
|
+
}
|
|
16
|
+
export interface IngestToolResultInput {
|
|
17
|
+
sourceTool: string;
|
|
18
|
+
command?: string;
|
|
19
|
+
rawText: string;
|
|
20
|
+
contentType?: ContentType;
|
|
21
|
+
createdTurn: number;
|
|
22
|
+
}
|
|
23
|
+
export interface IngestToolResultOutput {
|
|
24
|
+
/** Text placed in LLM conversation history */
|
|
25
|
+
promptText: string;
|
|
26
|
+
artifactId?: string;
|
|
27
|
+
inlined: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface RetrieveArtifactOptions {
|
|
30
|
+
grep?: string;
|
|
31
|
+
lineStart?: number;
|
|
32
|
+
lineEnd?: number;
|
|
33
|
+
jsonPath?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface ToolCallRecord {
|
|
36
|
+
tool: string;
|
|
37
|
+
args: Record<string, unknown>;
|
|
38
|
+
resultArtifactId?: string;
|
|
39
|
+
isError: boolean;
|
|
40
|
+
/** Truncated tool result text for deterministic activity rules (full text in artifact store) */
|
|
41
|
+
resultText?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface TurnDigestDecision {
|
|
44
|
+
summary: string;
|
|
45
|
+
rationale?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface TurnDigest {
|
|
48
|
+
turnId: number;
|
|
49
|
+
userIntent: string;
|
|
50
|
+
filesChanged: string[];
|
|
51
|
+
filesWritten: string[];
|
|
52
|
+
artifactRefs: string[];
|
|
53
|
+
decisions: TurnDigestDecision[];
|
|
54
|
+
constraints: string[];
|
|
55
|
+
errorsNew: string[];
|
|
56
|
+
errorsFixed: string[];
|
|
57
|
+
toolSummary: string;
|
|
58
|
+
/** Plan text extracted from the assistant message, if any */
|
|
59
|
+
extractedPlan?: string;
|
|
60
|
+
}
|
|
61
|
+
export type ActivityEntryType = "commit" | "test_pass" | "test_fail" | "error_fixed" | "file_written" | "decision_made";
|
|
62
|
+
export interface ActivityEntry {
|
|
63
|
+
turn: number;
|
|
64
|
+
type: ActivityEntryType;
|
|
65
|
+
summary: string;
|
|
66
|
+
artifactRef?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface StateSnapshot {
|
|
69
|
+
objects: Map<string, {
|
|
70
|
+
kind: string;
|
|
71
|
+
updated: number;
|
|
72
|
+
payloadJson: string;
|
|
73
|
+
}>;
|
|
74
|
+
}
|
|
75
|
+
export interface OpenError {
|
|
76
|
+
key: string;
|
|
77
|
+
message: string;
|
|
78
|
+
turn: number;
|
|
79
|
+
tool: string;
|
|
80
|
+
command?: string;
|
|
81
|
+
}
|
|
82
|
+
export interface CheckpointDraft {
|
|
83
|
+
lastUserIntent: string;
|
|
84
|
+
openErrors: OpenError[];
|
|
85
|
+
recentDecisions: Array<{
|
|
86
|
+
summary: string;
|
|
87
|
+
turn: number;
|
|
88
|
+
}>;
|
|
89
|
+
recentConstraints: string[];
|
|
90
|
+
recentActivity: ActivityEntry[];
|
|
91
|
+
}
|
|
92
|
+
/** When compact is true, summary renders as a one-liner; rationale is always retained. */
|
|
93
|
+
export interface CheckpointDecisionEntry {
|
|
94
|
+
summary: string;
|
|
95
|
+
rationale?: string;
|
|
96
|
+
turn: number;
|
|
97
|
+
compact?: boolean;
|
|
98
|
+
}
|
|
99
|
+
export interface CheckpointNarrativeEntry {
|
|
100
|
+
turn: number;
|
|
101
|
+
text: string;
|
|
102
|
+
}
|
|
103
|
+
export interface CheckpointPlanEntry {
|
|
104
|
+
text: string;
|
|
105
|
+
turn: number;
|
|
106
|
+
superseded: boolean;
|
|
107
|
+
supersededTurn?: number;
|
|
108
|
+
completed?: string[];
|
|
109
|
+
}
|
|
110
|
+
export interface CheckpointFileEntry {
|
|
111
|
+
path: string;
|
|
112
|
+
turn: number;
|
|
113
|
+
}
|
|
114
|
+
export interface CheckpointErrorEntry {
|
|
115
|
+
key: string;
|
|
116
|
+
message: string;
|
|
117
|
+
turn: number;
|
|
118
|
+
fixed: boolean;
|
|
119
|
+
fixedTurn?: number;
|
|
120
|
+
}
|
|
121
|
+
export interface CheckpointFindingEntry {
|
|
122
|
+
summary: string;
|
|
123
|
+
artifactRef?: string;
|
|
124
|
+
turn: number;
|
|
125
|
+
}
|
|
126
|
+
export interface CheckpointQuestionEntry {
|
|
127
|
+
text: string;
|
|
128
|
+
turn: number;
|
|
129
|
+
closed: boolean;
|
|
130
|
+
}
|
|
131
|
+
export interface CheckpointState {
|
|
132
|
+
activeRequest: string;
|
|
133
|
+
plans: CheckpointPlanEntry[];
|
|
134
|
+
constraints: string[];
|
|
135
|
+
decisions: CheckpointDecisionEntry[];
|
|
136
|
+
files: CheckpointFileEntry[];
|
|
137
|
+
findings: CheckpointFindingEntry[];
|
|
138
|
+
errors: CheckpointErrorEntry[];
|
|
139
|
+
questions: CheckpointQuestionEntry[];
|
|
140
|
+
activity: ActivityEntry[];
|
|
141
|
+
narrative: CheckpointNarrativeEntry[];
|
|
142
|
+
lastReconciledTurn: number;
|
|
143
|
+
}
|
|
144
|
+
export interface SessionCheckpoint {
|
|
145
|
+
version: 1;
|
|
146
|
+
state: CheckpointState;
|
|
147
|
+
}
|
|
148
|
+
export type ContextUnitType = "verbatim_turn" | "turn_digest" | "checkpoint_section" | "artifact_card" | "activity_entry" | "memory_digest" | "active_state";
|
|
149
|
+
export interface ContextUnit {
|
|
150
|
+
id: string;
|
|
151
|
+
type: ContextUnitType;
|
|
152
|
+
content: string;
|
|
153
|
+
tokens: number;
|
|
154
|
+
sourceTurn: number;
|
|
155
|
+
score: number;
|
|
156
|
+
pinned: boolean;
|
|
157
|
+
artifactRefs: string[];
|
|
158
|
+
}
|
|
159
|
+
export interface ScoreBreakdown {
|
|
160
|
+
pin: number;
|
|
161
|
+
recency: number;
|
|
162
|
+
relevance: number;
|
|
163
|
+
}
|
|
164
|
+
export interface ScoredContextUnit extends ContextUnit {
|
|
165
|
+
breakdown: ScoreBreakdown;
|
|
166
|
+
}
|
|
167
|
+
export type PressureMode = "normal" | "compact" | "emergency";
|
|
168
|
+
export interface CompileScoreRecord {
|
|
169
|
+
turn: number;
|
|
170
|
+
unitId: string;
|
|
171
|
+
type: ContextUnitType;
|
|
172
|
+
score: number;
|
|
173
|
+
included: boolean;
|
|
174
|
+
band: number;
|
|
175
|
+
tokens: number;
|
|
176
|
+
breakdown: ScoreBreakdown;
|
|
177
|
+
}
|
|
178
|
+
export interface TurnRecord {
|
|
179
|
+
turn: number;
|
|
180
|
+
userMessage: string;
|
|
181
|
+
assistantMessage: string;
|
|
182
|
+
toolCalls: ToolCallRecord[];
|
|
183
|
+
artifactIds: string[];
|
|
184
|
+
filesRead: string[];
|
|
185
|
+
filesWritten: string[];
|
|
186
|
+
errors: string[];
|
|
187
|
+
tokenCount: number;
|
|
188
|
+
timestamp: number;
|
|
189
|
+
}
|
|
190
|
+
export interface TurnSearchMatch {
|
|
191
|
+
turn: number;
|
|
192
|
+
score: number;
|
|
193
|
+
userMessage: string;
|
|
194
|
+
assistantMessage: string;
|
|
195
|
+
excerpt: string;
|
|
196
|
+
artifactIds: string[];
|
|
197
|
+
filesRead: string[];
|
|
198
|
+
filesWritten: string[];
|
|
199
|
+
errors: string[];
|
|
200
|
+
timestamp: number;
|
|
201
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CompilerConfig } from "./types.js";
|
|
2
|
+
export { DEFAULT_MODEL_CONTEXT_WINDOW, resolveContextWindowSync, fetchAndCacheContextWindow, } from "./model-context.js";
|
|
3
|
+
export declare function resolveCompactionConfig(config: CompilerConfig): {
|
|
4
|
+
autoCompactAt: number;
|
|
5
|
+
autoCompactClearAt: number;
|
|
6
|
+
compactChunkFraction: number;
|
|
7
|
+
verbatimOnly: boolean;
|
|
8
|
+
};
|
|
9
|
+
/** Prompt fill ratio against usable context (window minus reserved output). */
|
|
10
|
+
export declare function computeContextPressureRatio(usedTokens: number, contextWindowTokens: number, reservedOutputTokens?: number): number;
|
|
11
|
+
/**
|
|
12
|
+
* Hysteresis: arm at auto_compact_at, disarm below auto_compact_clear_at.
|
|
13
|
+
* Trigger compaction only while armed and still at/above compact_at.
|
|
14
|
+
*/
|
|
15
|
+
export declare function shouldTriggerAutoCompact(pressureRatio: number, config: CompilerConfig, armed: boolean): {
|
|
16
|
+
trigger: boolean;
|
|
17
|
+
armed: boolean;
|
|
18
|
+
};
|
|
19
|
+
export declare function effectiveCompileBudget(tokenBudget: number, contextWindowTokens: number, reservedOutputTokens?: number): number;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export { DEFAULT_MODEL_CONTEXT_WINDOW, resolveContextWindowSync, fetchAndCacheContextWindow, } from "./model-context.js";
|
|
2
|
+
export function resolveCompactionConfig(config) {
|
|
3
|
+
return {
|
|
4
|
+
autoCompactAt: config.auto_compact_at ?? config.compression_watermark ?? 0.75,
|
|
5
|
+
autoCompactClearAt: config.auto_compact_clear_at ?? 0.55,
|
|
6
|
+
compactChunkFraction: config.compact_chunk_fraction ?? config.compression_flush_fraction ?? 0.25,
|
|
7
|
+
verbatimOnly: config.verbatim_only ?? false,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/** Prompt fill ratio against usable context (window minus reserved output). */
|
|
11
|
+
export function computeContextPressureRatio(usedTokens, contextWindowTokens, reservedOutputTokens = 0) {
|
|
12
|
+
const usable = Math.max(1, contextWindowTokens - reservedOutputTokens);
|
|
13
|
+
return usedTokens / usable;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Hysteresis: arm at auto_compact_at, disarm below auto_compact_clear_at.
|
|
17
|
+
* Trigger compaction only while armed and still at/above compact_at.
|
|
18
|
+
*/
|
|
19
|
+
export function shouldTriggerAutoCompact(pressureRatio, config, armed) {
|
|
20
|
+
const { autoCompactAt, autoCompactClearAt, verbatimOnly } = resolveCompactionConfig(config);
|
|
21
|
+
if (verbatimOnly)
|
|
22
|
+
return { trigger: false, armed };
|
|
23
|
+
let nextArmed = armed;
|
|
24
|
+
if (pressureRatio >= autoCompactAt)
|
|
25
|
+
nextArmed = true;
|
|
26
|
+
else if (pressureRatio < autoCompactClearAt)
|
|
27
|
+
nextArmed = false;
|
|
28
|
+
return {
|
|
29
|
+
trigger: nextArmed && pressureRatio >= autoCompactAt,
|
|
30
|
+
armed: nextArmed,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function effectiveCompileBudget(tokenBudget, contextWindowTokens, reservedOutputTokens = 0) {
|
|
34
|
+
const windowBudget = Math.max(0, contextWindowTokens - reservedOutputTokens);
|
|
35
|
+
return Math.max(0, Math.min(tokenBudget, windowBudget));
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Distiller, DistillerIntensity } from "../context-engine/distiller.js";
|
|
2
|
+
import type { ContentType } from "../context-engine/types.js";
|
|
3
|
+
export declare class GenericDistiller implements Distiller {
|
|
4
|
+
readonly name = "generic";
|
|
5
|
+
readonly contentTypes: ContentType[];
|
|
6
|
+
readonly mode: "sync";
|
|
7
|
+
distill(input: string, intensity: DistillerIntensity, contentType?: ContentType): string;
|
|
8
|
+
}
|
|
9
|
+
export declare class LogDistiller implements Distiller {
|
|
10
|
+
readonly name = "log";
|
|
11
|
+
readonly contentTypes: ContentType[];
|
|
12
|
+
readonly mode: "sync";
|
|
13
|
+
distill(input: string, intensity: DistillerIntensity): string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
function headTail(input, headChars, tailChars) {
|
|
2
|
+
if (input.length <= headChars + tailChars + 40)
|
|
3
|
+
return input;
|
|
4
|
+
const head = input.slice(0, headChars).trimEnd();
|
|
5
|
+
const tail = input.slice(-tailChars).trimStart();
|
|
6
|
+
const omitted = input.length - head.length - tail.length;
|
|
7
|
+
return `${head}\n… [${omitted.toLocaleString()} chars omitted] …\n${tail}`;
|
|
8
|
+
}
|
|
9
|
+
function summarizeJson(input, intensity) {
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(input);
|
|
12
|
+
const budget = intensity === "full" ? 8 : 16;
|
|
13
|
+
return JSON.stringify(compactJson(parsed, budget), null, 2);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return headTail(input, intensity === "full" ? 250 : 400, intensity === "full" ? 250 : 400);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function compactJson(value, budget) {
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
if (value.length <= budget)
|
|
22
|
+
return value.map((item) => compactJson(item, budget));
|
|
23
|
+
return [
|
|
24
|
+
...value.slice(0, budget).map((item) => compactJson(item, budget)),
|
|
25
|
+
{
|
|
26
|
+
__aria_summary: `${value.length - budget} array item(s) omitted`,
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
if (value !== null && typeof value === "object") {
|
|
31
|
+
const entries = Object.entries(value);
|
|
32
|
+
const out = {};
|
|
33
|
+
for (const [key, child] of entries.slice(0, budget)) {
|
|
34
|
+
out[key] = compactJson(child, budget);
|
|
35
|
+
}
|
|
36
|
+
if (entries.length > budget) {
|
|
37
|
+
out.__aria_summary = `${entries.length - budget} object field(s) omitted`;
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
export class GenericDistiller {
|
|
44
|
+
name = "generic";
|
|
45
|
+
contentTypes = ["other", "code", "prose", "json"];
|
|
46
|
+
mode = "sync";
|
|
47
|
+
distill(input, intensity, contentType) {
|
|
48
|
+
if (contentType === "json") {
|
|
49
|
+
return summarizeJson(input, intensity);
|
|
50
|
+
}
|
|
51
|
+
const head = intensity === "full" ? 250 : 400;
|
|
52
|
+
const tail = intensity === "full" ? 250 : 400;
|
|
53
|
+
return headTail(input, head, tail);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export class LogDistiller {
|
|
57
|
+
name = "log";
|
|
58
|
+
contentTypes = ["log"];
|
|
59
|
+
mode = "sync";
|
|
60
|
+
distill(input, intensity) {
|
|
61
|
+
const lines = input.split("\n");
|
|
62
|
+
const counts = new Map();
|
|
63
|
+
const errors = [];
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
const trimmed = line.trim();
|
|
66
|
+
if (!trimmed)
|
|
67
|
+
continue;
|
|
68
|
+
counts.set(trimmed, (counts.get(trimmed) ?? 0) + 1);
|
|
69
|
+
if (/\b(error|exception|fatal)\b/i.test(trimmed)) {
|
|
70
|
+
errors.push(trimmed);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const maxUnique = intensity === "full" ? 8 : 15;
|
|
74
|
+
const uniqueLines = [];
|
|
75
|
+
for (const [line, count] of counts) {
|
|
76
|
+
if (count === 1)
|
|
77
|
+
uniqueLines.push(line);
|
|
78
|
+
else
|
|
79
|
+
uniqueLines.push(`${line} (×${count})`);
|
|
80
|
+
if (uniqueLines.length >= maxUnique)
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
const tailErrors = errors.slice(-5);
|
|
84
|
+
const parts = [
|
|
85
|
+
`Log: ${lines.length} lines, ${counts.size} unique patterns`,
|
|
86
|
+
...uniqueLines,
|
|
87
|
+
];
|
|
88
|
+
if (tailErrors.length > 0) {
|
|
89
|
+
parts.push("Recent errors:", ...tailErrors);
|
|
90
|
+
}
|
|
91
|
+
return parts.join("\n");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Distiller, DistillerIntensity } from "../context-engine/distiller.js";
|
|
2
|
+
import type { ContentType } from "../context-engine/types.js";
|
|
3
|
+
export declare class DiffDistiller implements Distiller {
|
|
4
|
+
readonly name = "git-diff";
|
|
5
|
+
readonly contentTypes: ContentType[];
|
|
6
|
+
readonly mode: "sync";
|
|
7
|
+
distill(input: string, intensity: DistillerIntensity): string;
|
|
8
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const CONTEXT_LINES = 2;
|
|
2
|
+
export class DiffDistiller {
|
|
3
|
+
name = "git-diff";
|
|
4
|
+
contentTypes = ["diff"];
|
|
5
|
+
mode = "sync";
|
|
6
|
+
distill(input, intensity) {
|
|
7
|
+
const context = intensity === "full" ? 1 : CONTEXT_LINES;
|
|
8
|
+
const lines = input.split("\n");
|
|
9
|
+
const out = [];
|
|
10
|
+
let inHunk = false;
|
|
11
|
+
let hunkBuffer = [];
|
|
12
|
+
let hunkHasChange = false;
|
|
13
|
+
let metadataBuffer = [];
|
|
14
|
+
const flushMetadata = () => {
|
|
15
|
+
if (metadataBuffer.length > 0) {
|
|
16
|
+
out.push(...metadataBuffer);
|
|
17
|
+
metadataBuffer = [];
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const flushHunk = () => {
|
|
21
|
+
if (!hunkHasChange) {
|
|
22
|
+
inHunk = false;
|
|
23
|
+
hunkBuffer = [];
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
flushMetadata();
|
|
27
|
+
const compact = compactHunk(hunkBuffer, context);
|
|
28
|
+
if (compact.length > 0)
|
|
29
|
+
out.push(...compact);
|
|
30
|
+
inHunk = false;
|
|
31
|
+
hunkBuffer = [];
|
|
32
|
+
hunkHasChange = false;
|
|
33
|
+
};
|
|
34
|
+
for (const line of lines) {
|
|
35
|
+
if (line.startsWith("diff --git ")) {
|
|
36
|
+
flushHunk();
|
|
37
|
+
flushMetadata();
|
|
38
|
+
out.push(line);
|
|
39
|
+
metadataBuffer = [];
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (line.startsWith("@@")) {
|
|
43
|
+
flushHunk();
|
|
44
|
+
flushMetadata();
|
|
45
|
+
inHunk = true;
|
|
46
|
+
hunkBuffer = [line];
|
|
47
|
+
hunkHasChange = false;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (inHunk) {
|
|
51
|
+
if (line.startsWith("+") && !line.startsWith("+++"))
|
|
52
|
+
hunkHasChange = true;
|
|
53
|
+
if (line.startsWith("-") && !line.startsWith("---"))
|
|
54
|
+
hunkHasChange = true;
|
|
55
|
+
hunkBuffer.push(line);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (intensity !== "full") {
|
|
59
|
+
out.push(line);
|
|
60
|
+
}
|
|
61
|
+
else if (isDiffMetadata(line)) {
|
|
62
|
+
metadataBuffer.push(line);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
flushHunk();
|
|
66
|
+
flushMetadata();
|
|
67
|
+
if (out.length === 0)
|
|
68
|
+
return input.slice(0, 1200);
|
|
69
|
+
return out.join("\n");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function isDiffMetadata(line) {
|
|
73
|
+
return (line.startsWith("index ") ||
|
|
74
|
+
line.startsWith("old mode ") ||
|
|
75
|
+
line.startsWith("new mode ") ||
|
|
76
|
+
line.startsWith("deleted file mode ") ||
|
|
77
|
+
line.startsWith("new file mode ") ||
|
|
78
|
+
line.startsWith("similarity index ") ||
|
|
79
|
+
line.startsWith("dissimilarity index ") ||
|
|
80
|
+
line.startsWith("rename from ") ||
|
|
81
|
+
line.startsWith("rename to ") ||
|
|
82
|
+
line.startsWith("copy from ") ||
|
|
83
|
+
line.startsWith("copy to ") ||
|
|
84
|
+
line.startsWith("Binary files ") ||
|
|
85
|
+
line.startsWith("--- ") ||
|
|
86
|
+
line.startsWith("+++ "));
|
|
87
|
+
}
|
|
88
|
+
function compactHunk(lines, context) {
|
|
89
|
+
const changeIndexes = [];
|
|
90
|
+
for (let i = 0; i < lines.length; i++) {
|
|
91
|
+
const line = lines[i];
|
|
92
|
+
if (line.startsWith("+") || line.startsWith("-")) {
|
|
93
|
+
if (!line.startsWith("+++") && !line.startsWith("---")) {
|
|
94
|
+
changeIndexes.push(i);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (changeIndexes.length === 0)
|
|
99
|
+
return [];
|
|
100
|
+
const keep = new Set();
|
|
101
|
+
keep.add(0);
|
|
102
|
+
for (const idx of changeIndexes) {
|
|
103
|
+
for (let d = -context; d <= context; d++) {
|
|
104
|
+
const pos = idx + d;
|
|
105
|
+
if (pos >= 0 && pos < lines.length)
|
|
106
|
+
keep.add(pos);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const sorted = [...keep].sort((a, b) => a - b);
|
|
110
|
+
const out = [];
|
|
111
|
+
let prev = -2;
|
|
112
|
+
for (const idx of sorted) {
|
|
113
|
+
if (idx > prev + 1)
|
|
114
|
+
out.push("…");
|
|
115
|
+
out.push(lines[idx]);
|
|
116
|
+
prev = idx;
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DiffDistiller } from "./git-diff.js";
|
|
2
|
+
import { GenericDistiller, LogDistiller } from "./generic.js";
|
|
3
|
+
import { TestDistiller } from "./npm-test.js";
|
|
4
|
+
import { SearchDistiller } from "./rg-results.js";
|
|
5
|
+
import { BuildDistiller } from "./tsc-errors.js";
|
|
6
|
+
import { DistillerRegistry } from "../context-engine/distiller.js";
|
|
7
|
+
export function createDefaultDistillerRegistry() {
|
|
8
|
+
const registry = new DistillerRegistry();
|
|
9
|
+
registry.register(new DiffDistiller());
|
|
10
|
+
registry.register(new TestDistiller());
|
|
11
|
+
registry.register(new BuildDistiller());
|
|
12
|
+
registry.register(new SearchDistiller());
|
|
13
|
+
registry.register(new LogDistiller());
|
|
14
|
+
registry.register(new GenericDistiller());
|
|
15
|
+
return registry;
|
|
16
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Distiller, DistillerIntensity } from "../context-engine/distiller.js";
|
|
2
|
+
import type { ContentType } from "../context-engine/types.js";
|
|
3
|
+
export declare class TestDistiller implements Distiller {
|
|
4
|
+
readonly name = "npm-test";
|
|
5
|
+
readonly contentTypes: ContentType[];
|
|
6
|
+
readonly mode: "sync";
|
|
7
|
+
distill(input: string, intensity: DistillerIntensity): string;
|
|
8
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export class TestDistiller {
|
|
2
|
+
name = "npm-test";
|
|
3
|
+
contentTypes = ["test_output"];
|
|
4
|
+
mode = "sync";
|
|
5
|
+
distill(input, intensity) {
|
|
6
|
+
const lines = input.split("\n");
|
|
7
|
+
const failures = [];
|
|
8
|
+
const summaries = [];
|
|
9
|
+
let captureFailure = false;
|
|
10
|
+
const failureLimit = intensity === "full" ? 80 : 140;
|
|
11
|
+
for (const line of lines) {
|
|
12
|
+
const trimmed = line.trim();
|
|
13
|
+
const isFailureStart = /^\s*(FAIL|✕|×)\s/.test(line) ||
|
|
14
|
+
/\bFAIL\b/.test(line) ||
|
|
15
|
+
/^AssertionError\b/.test(trimmed) ||
|
|
16
|
+
/^(TypeError|ReferenceError|Error):/.test(trimmed);
|
|
17
|
+
const isPassingSuite = /^\s*(PASS|✓)\s/.test(line);
|
|
18
|
+
const isSummary = /^(Test Files|Tests|Test Suites|Snapshots|Time):/.test(trimmed) ||
|
|
19
|
+
/^Tests:\s+/.test(trimmed) ||
|
|
20
|
+
/^\d+\s+(passed|failed)\b/i.test(trimmed);
|
|
21
|
+
if (isSummary) {
|
|
22
|
+
summaries.push(line);
|
|
23
|
+
if (/failed/i.test(line))
|
|
24
|
+
captureFailure = true;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (isPassingSuite) {
|
|
28
|
+
captureFailure = false;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (isFailureStart) {
|
|
32
|
+
captureFailure = true;
|
|
33
|
+
}
|
|
34
|
+
if (captureFailure && failures.length < failureLimit) {
|
|
35
|
+
failures.push(line);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const parts = [];
|
|
39
|
+
if (failures.length > 0) {
|
|
40
|
+
parts.push(`${failures.length} failure detail line(s):`, ...failures);
|
|
41
|
+
}
|
|
42
|
+
if (summaries.length > 0) {
|
|
43
|
+
parts.push("Summary:", ...summaries.slice(-6));
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
parts.push(`Test output: ${lines.length} lines`);
|
|
47
|
+
}
|
|
48
|
+
return parts.join("\n");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Distiller, DistillerIntensity } from "../context-engine/distiller.js";
|
|
2
|
+
import type { ContentType } from "../context-engine/types.js";
|
|
3
|
+
export declare class SearchDistiller implements Distiller {
|
|
4
|
+
readonly name = "rg-search";
|
|
5
|
+
readonly contentTypes: ContentType[];
|
|
6
|
+
readonly mode: "sync";
|
|
7
|
+
distill(input: string, intensity: DistillerIntensity): string;
|
|
8
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export class SearchDistiller {
|
|
2
|
+
name = "rg-search";
|
|
3
|
+
contentTypes = ["search_results"];
|
|
4
|
+
mode = "sync";
|
|
5
|
+
distill(input, intensity) {
|
|
6
|
+
const lines = input.split("\n").filter((l) => l.trim().length > 0);
|
|
7
|
+
const limit = intensity === "full" ? 15 : 30;
|
|
8
|
+
const seen = new Set();
|
|
9
|
+
const kept = [];
|
|
10
|
+
for (const line of lines) {
|
|
11
|
+
const normalized = line.replace(/\s+/g, " ").trim();
|
|
12
|
+
const key = normalized.slice(0, 120);
|
|
13
|
+
if (seen.has(key))
|
|
14
|
+
continue;
|
|
15
|
+
seen.add(key);
|
|
16
|
+
kept.push(line);
|
|
17
|
+
if (kept.length >= limit)
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
if (kept.length === 0)
|
|
21
|
+
return input.slice(0, 800);
|
|
22
|
+
const omitted = Math.max(0, lines.length - kept.length);
|
|
23
|
+
const header = omitted > 0
|
|
24
|
+
? `Search results: showing ${kept.length} of ${lines.length} lines`
|
|
25
|
+
: `Search results: ${kept.length} lines`;
|
|
26
|
+
return [header, ...kept].join("\n");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Distiller, DistillerIntensity } from "../context-engine/distiller.js";
|
|
2
|
+
import type { ContentType } from "../context-engine/types.js";
|
|
3
|
+
export declare class BuildDistiller implements Distiller {
|
|
4
|
+
readonly name = "tsc-errors";
|
|
5
|
+
readonly contentTypes: ContentType[];
|
|
6
|
+
readonly mode: "sync";
|
|
7
|
+
distill(input: string, intensity: DistillerIntensity): string;
|
|
8
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const ERROR_LINE = /^(.+?)\((\d+),(\d+)\):\s+error\s+(TS\d+):\s+(.+)$/;
|
|
2
|
+
export class BuildDistiller {
|
|
3
|
+
name = "tsc-errors";
|
|
4
|
+
contentTypes = ["build_output"];
|
|
5
|
+
mode = "sync";
|
|
6
|
+
distill(input, intensity) {
|
|
7
|
+
const lines = input.split("\n");
|
|
8
|
+
const groups = new Map();
|
|
9
|
+
const genericErrors = [];
|
|
10
|
+
for (const line of lines) {
|
|
11
|
+
const match = line.match(ERROR_LINE);
|
|
12
|
+
if (match) {
|
|
13
|
+
const [, file, lineNo, , code, message] = match;
|
|
14
|
+
const key = `${code}:${message.trim()}`;
|
|
15
|
+
const existing = groups.get(key);
|
|
16
|
+
if (existing) {
|
|
17
|
+
existing.locations.push(`${file}:${lineNo}`);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
groups.set(key, {
|
|
21
|
+
code,
|
|
22
|
+
message: message.trim(),
|
|
23
|
+
locations: [`${file}:${lineNo}`],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (/^error\b/i.test(line.trim()) && line.length < 300) {
|
|
29
|
+
genericErrors.push(line.trim());
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (groups.size === 0 && genericErrors.length === 0) {
|
|
33
|
+
return lines.slice(0, intensity === "full" ? 20 : 40).join("\n");
|
|
34
|
+
}
|
|
35
|
+
const maxGroups = intensity === "full" ? 25 : 50;
|
|
36
|
+
const maxLocationsPerGroup = intensity === "full" ? 20 : 50;
|
|
37
|
+
const rendered = [];
|
|
38
|
+
for (const group of groups.values()) {
|
|
39
|
+
const shownLocations = group.locations.slice(0, maxLocationsPerGroup);
|
|
40
|
+
const omitted = group.locations.length - shownLocations.length;
|
|
41
|
+
rendered.push(`${group.code} ${group.message}`, ` ${group.locations.length} location(s): ${shownLocations.join(", ")}${omitted > 0 ? `, ... ${omitted} more` : ""}`);
|
|
42
|
+
if (rendered.length / 2 >= maxGroups)
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
const totalLocations = [...groups.values()].reduce((sum, group) => sum + group.locations.length, 0) +
|
|
46
|
+
genericErrors.length;
|
|
47
|
+
const header = groups.size > 0
|
|
48
|
+
? `${groups.size} unique build error(s), ${totalLocations} location(s)`
|
|
49
|
+
: `${genericErrors.length} build error(s)`;
|
|
50
|
+
return [header, ...rendered, ...genericErrors].join("\n");
|
|
51
|
+
}
|
|
52
|
+
}
|