@thispointon/kondi-chat 0.1.2
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 +556 -0
- package/bin/kondi-chat +56 -0
- package/bin/kondi-chat.js +72 -0
- package/package.json +55 -0
- package/scripts/demo.tape +49 -0
- package/scripts/postinstall.cjs +103 -0
- package/src/audit/analytics.ts +261 -0
- package/src/audit/ledger.ts +253 -0
- package/src/audit/telemetry.ts +165 -0
- package/src/cli/backend.ts +675 -0
- package/src/cli/commands.ts +419 -0
- package/src/cli/help.ts +182 -0
- package/src/cli/submit-helpers.ts +159 -0
- package/src/cli/submit.ts +539 -0
- package/src/cli/wizard.ts +121 -0
- package/src/context/bootstrap.ts +138 -0
- package/src/context/budget.ts +100 -0
- package/src/context/manager.ts +666 -0
- package/src/context/memory.ts +160 -0
- package/src/context/preflight.ts +176 -0
- package/src/context/project-brain.ts +101 -0
- package/src/context/receipts.ts +108 -0
- package/src/context/skills.ts +154 -0
- package/src/context/symbol-index.ts +240 -0
- package/src/council/profiles.ts +137 -0
- package/src/council/tool.ts +138 -0
- package/src/council-engine/cli/council-artifacts.ts +230 -0
- package/src/council-engine/cli/council-config.ts +178 -0
- package/src/council-engine/cli/council-session-export.ts +116 -0
- package/src/council-engine/cli/kondi.ts +98 -0
- package/src/council-engine/cli/llm-caller.ts +229 -0
- package/src/council-engine/cli/localStorage-shim.ts +119 -0
- package/src/council-engine/cli/node-platform.ts +68 -0
- package/src/council-engine/cli/run-council.ts +481 -0
- package/src/council-engine/cli/run-pipeline.ts +772 -0
- package/src/council-engine/cli/session-export.ts +153 -0
- package/src/council-engine/configs/councils/analysis.json +101 -0
- package/src/council-engine/configs/councils/code-planning.json +86 -0
- package/src/council-engine/configs/councils/coding.json +89 -0
- package/src/council-engine/configs/councils/debate.json +97 -0
- package/src/council-engine/configs/councils/solo-claude.json +34 -0
- package/src/council-engine/configs/councils/solo-gpt.json +34 -0
- package/src/council-engine/council/coding-orchestrator.ts +1205 -0
- package/src/council-engine/council/context-bootstrap.ts +147 -0
- package/src/council-engine/council/context-inspection.ts +42 -0
- package/src/council-engine/council/context-store.ts +763 -0
- package/src/council-engine/council/deliberation-orchestrator.ts +2762 -0
- package/src/council-engine/council/factory.ts +164 -0
- package/src/council-engine/council/index.ts +201 -0
- package/src/council-engine/council/ledger-store.ts +438 -0
- package/src/council-engine/council/prompts.ts +1689 -0
- package/src/council-engine/council/storage-cleanup.ts +164 -0
- package/src/council-engine/council/store.ts +1110 -0
- package/src/council-engine/council/synthesis.ts +291 -0
- package/src/council-engine/council/types.ts +845 -0
- package/src/council-engine/council/validation.ts +613 -0
- package/src/council-engine/pipeline/build-detect.ts +73 -0
- package/src/council-engine/pipeline/executor.ts +1048 -0
- package/src/council-engine/pipeline/index.ts +9 -0
- package/src/council-engine/pipeline/install-detect.ts +84 -0
- package/src/council-engine/pipeline/memory-store.ts +182 -0
- package/src/council-engine/pipeline/output-parsers.ts +146 -0
- package/src/council-engine/pipeline/run-output.ts +149 -0
- package/src/council-engine/pipeline/session-import.ts +177 -0
- package/src/council-engine/pipeline/store.ts +753 -0
- package/src/council-engine/pipeline/test-detect.ts +82 -0
- package/src/council-engine/pipeline/types.ts +401 -0
- package/src/council-engine/services/deliberationSummary.ts +114 -0
- package/src/council-engine/tsconfig.json +16 -0
- package/src/council-engine/types/mcp.ts +122 -0
- package/src/council-engine/utils/filterTools.ts +73 -0
- package/src/engine/apply.ts +238 -0
- package/src/engine/checkpoints.ts +237 -0
- package/src/engine/consultants.ts +347 -0
- package/src/engine/diff.ts +171 -0
- package/src/engine/errors.ts +102 -0
- package/src/engine/git-tools.ts +246 -0
- package/src/engine/hooks.ts +181 -0
- package/src/engine/loop-guard.ts +155 -0
- package/src/engine/permissions.ts +293 -0
- package/src/engine/pipeline.ts +376 -0
- package/src/engine/sub-agents.ts +133 -0
- package/src/engine/task-card.ts +185 -0
- package/src/engine/task-router.ts +256 -0
- package/src/engine/task-store.ts +86 -0
- package/src/engine/tools.ts +783 -0
- package/src/engine/verify.ts +111 -0
- package/src/mcp/client.ts +225 -0
- package/src/mcp/config.ts +120 -0
- package/src/mcp/tool-manager.ts +192 -0
- package/src/mcp/types.ts +61 -0
- package/src/providers/llm-caller.ts +943 -0
- package/src/providers/rate-limiter.ts +238 -0
- package/src/router/NOTES.md +28 -0
- package/src/router/collector.ts +474 -0
- package/src/router/embeddings.ts +286 -0
- package/src/router/index.ts +299 -0
- package/src/router/intent-router.ts +225 -0
- package/src/router/nn-router.ts +205 -0
- package/src/router/profiles.ts +309 -0
- package/src/router/registry.ts +565 -0
- package/src/router/rules.ts +274 -0
- package/src/router/train.py +408 -0
- package/src/session/store.ts +211 -0
- package/src/test-utils/mock-llm.ts +39 -0
- package/src/types.ts +322 -0
- package/src/web/manager.ts +311 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Directory Context Bootstrap
|
|
3
|
+
*
|
|
4
|
+
* Scans a working directory to produce structured grounding context.
|
|
5
|
+
* Based on kondi-council's context-bootstrap.ts — simplified, two-tier.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { execSync } from 'node:child_process';
|
|
9
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
10
|
+
import { join, resolve } from 'node:path';
|
|
11
|
+
|
|
12
|
+
const MAX_FILE_SIZE = 2048;
|
|
13
|
+
|
|
14
|
+
const KEY_FILES = [
|
|
15
|
+
'README.md',
|
|
16
|
+
'package.json',
|
|
17
|
+
'Cargo.toml',
|
|
18
|
+
'tsconfig.json',
|
|
19
|
+
'.env.example',
|
|
20
|
+
'pyproject.toml',
|
|
21
|
+
'go.mod',
|
|
22
|
+
'Makefile',
|
|
23
|
+
'docker-compose.yml',
|
|
24
|
+
'Dockerfile',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const ENTRY_PATTERNS = [
|
|
28
|
+
'src/index.ts', 'src/index.js', 'src/index.tsx',
|
|
29
|
+
'src/main.ts', 'src/main.js', 'src/main.tsx', 'src/main.rs',
|
|
30
|
+
'src/app.ts', 'src/app.js', 'src/App.tsx',
|
|
31
|
+
'src/lib.rs',
|
|
32
|
+
'main.go', 'main.py', 'app.py',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const SOURCE_EXTENSIONS = ['.ts', '.js', '.tsx', '.jsx', '.py', '.rs', '.go', '.java', '.rb'];
|
|
36
|
+
|
|
37
|
+
export type BootstrapDepth = 'light' | 'deep';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Bootstrap directory context.
|
|
41
|
+
*
|
|
42
|
+
* - light: tree + key files (~10K chars, ~2.5K tokens)
|
|
43
|
+
* - deep: tree + key files + all source files (~120K chars, ~30K tokens)
|
|
44
|
+
*/
|
|
45
|
+
export async function bootstrapDirectory(
|
|
46
|
+
workingDir: string,
|
|
47
|
+
depth: BootstrapDepth = 'light',
|
|
48
|
+
): Promise<string> {
|
|
49
|
+
const maxTotalChars = depth === 'deep' ? 120_000 : 10_000;
|
|
50
|
+
const maxFiles = 80;
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
let tree = '';
|
|
54
|
+
let fileList: string[] = [];
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const raw = execSync(
|
|
58
|
+
`find . -maxdepth 4 -type f ` +
|
|
59
|
+
`-not -path '*/node_modules/*' -not -path '*/.git/*' ` +
|
|
60
|
+
`-not -path '*/target/*' -not -path '*/__pycache__/*' ` +
|
|
61
|
+
`-not -path '*/.next/*' -not -path '*/dist/*' ` +
|
|
62
|
+
`-not -path '*/package-lock.json' ` +
|
|
63
|
+
`| sort | head -${maxFiles}`,
|
|
64
|
+
{ cwd: workingDir, encoding: 'utf-8', timeout: 10_000 },
|
|
65
|
+
).trim();
|
|
66
|
+
tree = raw;
|
|
67
|
+
fileList = raw.split('\n').filter(Boolean);
|
|
68
|
+
} catch {
|
|
69
|
+
// find failed, continue
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const files: Array<{ name: string; content: string }> = [];
|
|
73
|
+
let totalChars = tree.length + 200;
|
|
74
|
+
const resolvedBase = resolve(workingDir);
|
|
75
|
+
|
|
76
|
+
// Key files first
|
|
77
|
+
for (const fileName of [...KEY_FILES, ...ENTRY_PATTERNS]) {
|
|
78
|
+
if (totalChars >= maxTotalChars) break;
|
|
79
|
+
const content = safeRead(workingDir, resolvedBase, fileName, MAX_FILE_SIZE);
|
|
80
|
+
if (content) {
|
|
81
|
+
files.push({ name: fileName, content });
|
|
82
|
+
totalChars += content.length + fileName.length + 20;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Deep mode: all source files
|
|
87
|
+
if (depth === 'deep' && fileList.length > 0) {
|
|
88
|
+
const keySet = new Set([...KEY_FILES, ...ENTRY_PATTERNS]);
|
|
89
|
+
const sourceFiles = fileList.filter(f =>
|
|
90
|
+
SOURCE_EXTENSIONS.some(ext => f.endsWith(ext)) &&
|
|
91
|
+
!Array.from(keySet).some(kf => f.endsWith(kf))
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
for (const relPath of sourceFiles) {
|
|
95
|
+
if (totalChars >= maxTotalChars) break;
|
|
96
|
+
const cleanPath = relPath.startsWith('./') ? relPath.slice(2) : relPath;
|
|
97
|
+
const maxSize = Math.min(4096, maxTotalChars - totalChars);
|
|
98
|
+
if (maxSize < 100) break;
|
|
99
|
+
const content = safeRead(workingDir, resolvedBase, cleanPath, maxSize);
|
|
100
|
+
if (content) {
|
|
101
|
+
files.push({ name: cleanPath, content });
|
|
102
|
+
totalChars += content.length + cleanPath.length + 20;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!tree && files.length === 0) return '';
|
|
108
|
+
|
|
109
|
+
const sections: string[] = [];
|
|
110
|
+
sections.push(`## Working Directory: ${workingDir}`);
|
|
111
|
+
if (tree) sections.push(`### File Tree\n\`\`\`\n${tree}\n\`\`\``);
|
|
112
|
+
if (files.length > 0) {
|
|
113
|
+
sections.push('### Files');
|
|
114
|
+
for (const f of files) {
|
|
115
|
+
sections.push(`#### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return sections.join('\n\n');
|
|
120
|
+
} catch (error) {
|
|
121
|
+
process.stderr.write(`[bootstrap] Failed: ${(error as Error).message}\n`);
|
|
122
|
+
return '';
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function safeRead(workingDir: string, base: string, fileName: string, maxSize: number): string | null {
|
|
127
|
+
try {
|
|
128
|
+
const filePath = join(workingDir.replace(/\/$/, ''), fileName);
|
|
129
|
+
const resolved = resolve(filePath);
|
|
130
|
+
if (!resolved.startsWith(base + '/') && resolved !== base) return null;
|
|
131
|
+
if (!existsSync(filePath)) return null;
|
|
132
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
133
|
+
if (!content) return null;
|
|
134
|
+
return content.length > maxSize ? content.slice(0, maxSize) + '\n... (truncated)' : content;
|
|
135
|
+
} catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Budget — assembles prompt context within a token budget.
|
|
3
|
+
*
|
|
4
|
+
* Fills from highest priority sections down. When budget is exceeded,
|
|
5
|
+
* compressible sections are marked for summarization and lower-priority
|
|
6
|
+
* sections are dropped entirely.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ContextSection } from '../types.ts';
|
|
10
|
+
|
|
11
|
+
/** Rough token estimate: ~4 chars per token for English text */
|
|
12
|
+
export function estimateTokens(text: string): number {
|
|
13
|
+
return Math.ceil(text.length / 4);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class ContextBudget {
|
|
17
|
+
private sections: ContextSection[] = [];
|
|
18
|
+
private budget: number;
|
|
19
|
+
private dropped: string[] = [];
|
|
20
|
+
private compressed: string[] = [];
|
|
21
|
+
|
|
22
|
+
constructor(tokenBudget: number) {
|
|
23
|
+
this.budget = tokenBudget;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Add a section to the context assembly */
|
|
27
|
+
add(key: string, content: string, priority: number, compressible = true): void {
|
|
28
|
+
if (!content || content.trim().length === 0) return;
|
|
29
|
+
this.sections.push({
|
|
30
|
+
key,
|
|
31
|
+
content,
|
|
32
|
+
priority,
|
|
33
|
+
compressible,
|
|
34
|
+
tokenEstimate: estimateTokens(content),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Assemble context within the token budget.
|
|
40
|
+
*
|
|
41
|
+
* Strategy:
|
|
42
|
+
* 1. Sort by priority (1 = highest, included first)
|
|
43
|
+
* 2. Include sections while under budget
|
|
44
|
+
* 3. When budget is tight, truncate compressible sections
|
|
45
|
+
* 4. Drop sections that don't fit at all
|
|
46
|
+
*
|
|
47
|
+
* Returns the assembled context string.
|
|
48
|
+
*/
|
|
49
|
+
assemble(): string {
|
|
50
|
+
this.dropped = [];
|
|
51
|
+
this.compressed = [];
|
|
52
|
+
|
|
53
|
+
// Sort by priority ascending (1 first)
|
|
54
|
+
const sorted = [...this.sections].sort((a, b) => a.priority - b.priority);
|
|
55
|
+
|
|
56
|
+
const included: ContextSection[] = [];
|
|
57
|
+
let usedTokens = 0;
|
|
58
|
+
|
|
59
|
+
for (const section of sorted) {
|
|
60
|
+
const remaining = this.budget - usedTokens;
|
|
61
|
+
|
|
62
|
+
if (section.tokenEstimate <= remaining) {
|
|
63
|
+
// Fits fully
|
|
64
|
+
included.push(section);
|
|
65
|
+
usedTokens += section.tokenEstimate;
|
|
66
|
+
} else if (section.compressible && remaining > 200) {
|
|
67
|
+
// Partially fits — truncate to remaining budget
|
|
68
|
+
const charLimit = remaining * 4;
|
|
69
|
+
const truncated = section.content.slice(0, charLimit) + '\n\n[... truncated ...]';
|
|
70
|
+
included.push({
|
|
71
|
+
...section,
|
|
72
|
+
content: truncated,
|
|
73
|
+
tokenEstimate: estimateTokens(truncated),
|
|
74
|
+
});
|
|
75
|
+
usedTokens += estimateTokens(truncated);
|
|
76
|
+
this.compressed.push(section.key);
|
|
77
|
+
} else {
|
|
78
|
+
// Doesn't fit
|
|
79
|
+
this.dropped.push(section.key);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return included.map(s => s.content).join('\n\n---\n\n');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Sections that were dropped due to budget */
|
|
87
|
+
getDropped(): string[] {
|
|
88
|
+
return this.dropped;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Sections that were truncated to fit */
|
|
92
|
+
getCompressed(): string[] {
|
|
93
|
+
return this.compressed;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Total estimated tokens of all sections before budget enforcement */
|
|
97
|
+
getTotalEstimate(): number {
|
|
98
|
+
return this.sections.reduce((sum, s) => sum + s.tokenEstimate, 0);
|
|
99
|
+
}
|
|
100
|
+
}
|