koneck 2.0.0 → 2.2.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/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +222 -0
- package/dist/chat.js.map +1 -1
- package/dist/code-graph.d.ts +1 -0
- package/dist/code-graph.d.ts.map +1 -1
- package/dist/code-graph.js +94 -56
- package/dist/code-graph.js.map +1 -1
- package/dist/debugger.d.ts +4 -0
- package/dist/debugger.d.ts.map +1 -0
- package/dist/debugger.js +104 -0
- package/dist/debugger.js.map +1 -0
- package/dist/diff-review.d.ts +13 -0
- package/dist/diff-review.d.ts.map +1 -0
- package/dist/diff-review.js +115 -0
- package/dist/diff-review.js.map +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +63 -3
- package/dist/engine.js.map +1 -1
- package/dist/explain.d.ts +5 -0
- package/dist/explain.d.ts.map +1 -0
- package/dist/explain.js +58 -0
- package/dist/explain.js.map +1 -0
- package/dist/index.js +159 -0
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +7 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +89 -2
- package/dist/memory.js.map +1 -1
- package/dist/plugin-packs.d.ts +14 -0
- package/dist/plugin-packs.d.ts.map +1 -0
- package/dist/plugin-packs.js +136 -0
- package/dist/plugin-packs.js.map +1 -0
- package/dist/refactor.d.ts +10 -0
- package/dist/refactor.d.ts.map +1 -0
- package/dist/refactor.js +182 -0
- package/dist/refactor.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +209 -0
- package/dist/server.js.map +1 -0
- package/dist/test-gen.d.ts +3 -0
- package/dist/test-gen.d.ts.map +1 -0
- package/dist/test-gen.js +136 -0
- package/dist/test-gen.js.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface PluginPack {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
detectPattern: string[];
|
|
5
|
+
systemPromptAddition: string;
|
|
6
|
+
toolHints: string[];
|
|
7
|
+
conventions: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare const PLUGIN_PACKS: Record<string, PluginPack>;
|
|
10
|
+
export declare function detectActivePacks(cwd: string): Promise<PluginPack[]>;
|
|
11
|
+
export declare function getPackSystemPrompt(cwd: string): Promise<string>;
|
|
12
|
+
export declare function listPluginPacks(): Promise<void>;
|
|
13
|
+
export declare function installPluginPack(packName: string, cwd: string): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=plugin-packs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-packs.d.ts","sourceRoot":"","sources":["../src/plugin-packs.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAwEnD,CAAC;AAEF,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAO1E;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOtE;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAiBrD;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BpF"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { globby } from 'globby';
|
|
5
|
+
import { appendMemory } from './memory.js';
|
|
6
|
+
export const PLUGIN_PACKS = {
|
|
7
|
+
react: {
|
|
8
|
+
name: 'React',
|
|
9
|
+
description: 'React component and hooks patterns',
|
|
10
|
+
detectPattern: ['src/**/*.tsx', 'src/**/*.jsx'],
|
|
11
|
+
systemPromptAddition: `Use functional components exclusively — no class components. Define all hooks (useState, useEffect, useMemo, useCallback) before any JSX. Keep derived state out of useState; compute it inline or with useMemo. Avoid direct DOM manipulation; use refs only for imperative APIs (focus, animation). Memoize expensive renders with React.memo and costly computations with useMemo. Extract repeated logic into custom hooks. Prefer composition over prop-drilling; reach for Context only for truly global state.`,
|
|
12
|
+
toolHints: ['Search for existing hooks before creating new ones', 'Check component exports are named, not default where possible'],
|
|
13
|
+
conventions: ['Functional components only', 'Hooks before JSX', 'Co-locate component state', 'No direct DOM manipulation'],
|
|
14
|
+
},
|
|
15
|
+
nextjs: {
|
|
16
|
+
name: 'Next.js',
|
|
17
|
+
description: 'Next.js App Router and Pages Router conventions',
|
|
18
|
+
detectPattern: ['pages/**', 'app/**', 'next.config.*'],
|
|
19
|
+
systemPromptAddition: `Default to Server Components in the App Router — add "use client" only when you need browser APIs, event handlers, or React state/effects. Keep data-fetching in server components or route handlers; never expose credentials to the client. Use next/image for all images (automatic optimization). Use next/link for internal navigation. Prefer generateStaticParams + static rendering for content that rarely changes. Use route groups (parentheses directories) to share layouts without affecting the URL.`,
|
|
20
|
+
toolHints: ['Distinguish app/ vs pages/ routing before editing', 'Check for middleware.ts at project root'],
|
|
21
|
+
conventions: ['Server components by default', '"use client" only when required', 'File-based routing — match URL structure', 'next/image and next/link over raw HTML'],
|
|
22
|
+
},
|
|
23
|
+
typescript: {
|
|
24
|
+
name: 'TypeScript',
|
|
25
|
+
description: 'TypeScript strict-mode patterns and type safety',
|
|
26
|
+
detectPattern: ['tsconfig.json'],
|
|
27
|
+
systemPromptAddition: `Always enable strict mode. Provide explicit return types on all exported functions and class methods. Prefer interfaces for object shapes that may be extended; use type aliases for unions, intersections, and mapped types. Never use any — use unknown and narrow it, or unknown[] over any[]. Avoid non-null assertion (!); prefer optional chaining and nullish coalescing. Use const assertions (as const) for literal tuples and enums.`,
|
|
28
|
+
toolHints: ['Run tsc --noEmit to check types before finalising', 'Check tsconfig.json paths for aliases'],
|
|
29
|
+
conventions: ['Strict mode always on', 'Explicit return types on public APIs', 'No `any` — use `unknown` and narrow', 'Prefer `interface` for extendable shapes'],
|
|
30
|
+
},
|
|
31
|
+
prisma: {
|
|
32
|
+
name: 'Prisma',
|
|
33
|
+
description: 'Prisma ORM query patterns and migration safety',
|
|
34
|
+
detectPattern: ['prisma/schema.prisma'],
|
|
35
|
+
systemPromptAddition: `Never write raw SQL — use Prisma Client methods. Wrap all multi-table writes in prisma.$transaction(). Always handle the P2002 unique constraint error when creating records that could conflict. Use select/include explicitly rather than fetching entire records. Run prisma migrate dev in development; prisma migrate deploy in CI/CD. Keep the schema file as the single source of truth — do not edit the database directly.`,
|
|
36
|
+
toolHints: ['Read prisma/schema.prisma before writing queries', 'Check for existing relations before adding new ones'],
|
|
37
|
+
conventions: ['Never raw SQL', 'Transactions for multi-table writes', 'Handle P2002 uniqueness errors', 'Explicit select/include — no over-fetching'],
|
|
38
|
+
},
|
|
39
|
+
terraform: {
|
|
40
|
+
name: 'Terraform',
|
|
41
|
+
description: 'Terraform IaC patterns and remote state management',
|
|
42
|
+
detectPattern: ['*.tf', '**/*.tf'],
|
|
43
|
+
systemPromptAddition: `Organise infrastructure into reusable modules; call them from a root module. Tag every resource with at minimum: project, environment, managed-by=terraform. Store state in a remote backend (S3+DynamoDB, GCS, or Terraform Cloud) — never commit .tfstate files. Never hardcode secrets; use variable inputs sourced from a secrets manager or CI environment. Run terraform fmt and terraform validate before every plan. Use terraform plan output files (-out=tfplan) to guarantee apply matches the reviewed plan.`,
|
|
44
|
+
toolHints: ['Check for existing modules before adding resources', 'Verify backend config in terraform block'],
|
|
45
|
+
conventions: ['Use modules for reusable patterns', 'Tag all resources', 'Remote state backend mandatory', 'No hardcoded secrets'],
|
|
46
|
+
},
|
|
47
|
+
django: {
|
|
48
|
+
name: 'Django',
|
|
49
|
+
description: 'Django ORM, views, and application structure',
|
|
50
|
+
detectPattern: ['manage.py', '**/settings.py'],
|
|
51
|
+
systemPromptAddition: `Use the Django ORM exclusively — no raw SQL unless profiling proves it necessary, and even then wrap it in connection.execute with parameterised queries. Keep views thin: move business logic to service functions or model methods. Use Django signals only for cross-app side effects, not within the same app. Always use select_related and prefetch_related to avoid N+1 queries. Validate data with forms or serialisers before it reaches the model. Use environment variables (via django-environ or python-decouple) for all settings that vary between environments.`,
|
|
52
|
+
toolHints: ['Check INSTALLED_APPS before adding new models', 'Verify migration state before schema changes'],
|
|
53
|
+
conventions: ['Use ORM — no raw SQL', 'Thin views, fat models/services', 'Signals for cross-app effects only', 'select_related/prefetch_related to avoid N+1'],
|
|
54
|
+
},
|
|
55
|
+
postgres: {
|
|
56
|
+
name: 'PostgreSQL',
|
|
57
|
+
description: 'PostgreSQL query optimisation and migration practices',
|
|
58
|
+
detectPattern: ['migrations/**', '**/*.sql'],
|
|
59
|
+
systemPromptAddition: `Always add indexes on foreign key columns — PostgreSQL does not create them automatically. Use EXPLAIN ANALYZE to verify query plans before committing optimisations. Wrap multi-step writes in explicit transactions (BEGIN/COMMIT). Prefer UPSERT (INSERT ... ON CONFLICT) over separate SELECT+INSERT. Use SERIAL or IDENTITY columns for surrogate keys, not application-generated UUIDs unless globally unique IDs are required. Never run DDL (ALTER TABLE, DROP) directly in production without a tested rollback script.`,
|
|
60
|
+
toolHints: ['Check for existing indexes before adding new ones', 'Review EXPLAIN ANALYZE output for seq scans on large tables'],
|
|
61
|
+
conventions: ['Index all foreign keys', 'EXPLAIN ANALYZE before optimising', 'Transactions for multi-step writes', 'Rollback script before DDL in production'],
|
|
62
|
+
},
|
|
63
|
+
docker: {
|
|
64
|
+
name: 'Docker',
|
|
65
|
+
description: 'Dockerfile best practices and Compose patterns',
|
|
66
|
+
detectPattern: ['Dockerfile', 'docker-compose.yml', 'docker-compose.yaml', 'compose.yml'],
|
|
67
|
+
systemPromptAddition: `Use multi-stage builds to keep production images small — build in one stage, copy artefacts into a minimal runtime image. Run processes as a non-root user; add a dedicated user in the Dockerfile and switch with USER. Pin base image versions to specific digests or tags (never use latest in production). Order layers from least to most frequently changed to maximise cache reuse. Use .dockerignore to exclude node_modules, .git, and build artefacts. In Compose, use named volumes for persistent data and healthchecks for service dependencies.`,
|
|
68
|
+
toolHints: ['Check .dockerignore exists before building', 'Verify non-root USER instruction is present'],
|
|
69
|
+
conventions: ['Multi-stage builds', 'Non-root user', 'Pin image versions', 'Layer order: deps before source'],
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
export async function detectActivePacks(cwd) {
|
|
73
|
+
const active = [];
|
|
74
|
+
for (const pack of Object.values(PLUGIN_PACKS)) {
|
|
75
|
+
const matches = await globby(pack.detectPattern, { cwd, onlyFiles: false });
|
|
76
|
+
if (matches.length > 0)
|
|
77
|
+
active.push(pack);
|
|
78
|
+
}
|
|
79
|
+
return active;
|
|
80
|
+
}
|
|
81
|
+
export async function getPackSystemPrompt(cwd) {
|
|
82
|
+
const active = await detectActivePacks(cwd);
|
|
83
|
+
if (active.length === 0)
|
|
84
|
+
return '';
|
|
85
|
+
const sections = active
|
|
86
|
+
.map(p => `### ${p.name}\n${p.systemPromptAddition}`)
|
|
87
|
+
.join('\n\n');
|
|
88
|
+
return `## Framework context (auto-detected)\n\n${sections}`;
|
|
89
|
+
}
|
|
90
|
+
export async function listPluginPacks() {
|
|
91
|
+
console.log(chalk.bold('\nAvailable plugin packs:\n'));
|
|
92
|
+
const nameW = 12;
|
|
93
|
+
const descW = 44;
|
|
94
|
+
const header = chalk.cyan('Name'.padEnd(nameW)) +
|
|
95
|
+
chalk.cyan('Description'.padEnd(descW)) +
|
|
96
|
+
chalk.cyan('Detect patterns');
|
|
97
|
+
console.log(header);
|
|
98
|
+
console.log('─'.repeat(nameW + descW + 40));
|
|
99
|
+
for (const pack of Object.values(PLUGIN_PACKS)) {
|
|
100
|
+
const name = chalk.green(pack.name.padEnd(nameW));
|
|
101
|
+
const desc = pack.description.padEnd(descW);
|
|
102
|
+
const patterns = chalk.dim(pack.detectPattern.join(', '));
|
|
103
|
+
console.log(`${name}${desc}${patterns}`);
|
|
104
|
+
}
|
|
105
|
+
console.log();
|
|
106
|
+
}
|
|
107
|
+
export async function installPluginPack(packName, cwd) {
|
|
108
|
+
const pack = PLUGIN_PACKS[packName];
|
|
109
|
+
if (!pack) {
|
|
110
|
+
console.error(chalk.red(`Unknown plugin pack: ${packName}`));
|
|
111
|
+
console.error(chalk.dim(`Available: ${Object.keys(PLUGIN_PACKS).join(', ')}`));
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
// Append conventions to MEMORY.md
|
|
115
|
+
const conventionBlock = pack.conventions.map(c => `- ${c}`).join('\n');
|
|
116
|
+
await appendMemory(cwd, `${pack.name} conventions:\n${conventionBlock}`, 'conventions');
|
|
117
|
+
// Update packs.json
|
|
118
|
+
const packsFile = path.join(cwd, '.koneck', 'packs.json');
|
|
119
|
+
let installed = [];
|
|
120
|
+
try {
|
|
121
|
+
const raw = await fs.readFile(packsFile, 'utf-8');
|
|
122
|
+
installed = JSON.parse(raw);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// file absent — start fresh
|
|
126
|
+
}
|
|
127
|
+
if (!installed.includes(packName)) {
|
|
128
|
+
installed.push(packName);
|
|
129
|
+
await fs.mkdir(path.dirname(packsFile), { recursive: true });
|
|
130
|
+
await fs.writeFile(packsFile, JSON.stringify(installed, null, 2) + '\n', 'utf-8');
|
|
131
|
+
}
|
|
132
|
+
console.log(chalk.green(`✔ Installed ${chalk.bold(pack.name)} pack`));
|
|
133
|
+
console.log(chalk.dim(` Conventions added to .koneck/MEMORY.md`));
|
|
134
|
+
console.log(chalk.dim(` Pack recorded in .koneck/packs.json`));
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=plugin-packs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-packs.js","sourceRoot":"","sources":["../src/plugin-packs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAW3C,MAAM,CAAC,MAAM,YAAY,GAA+B;IACtD,KAAK,EAAE;QACL,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,oCAAoC;QACjD,aAAa,EAAE,CAAC,cAAc,EAAE,cAAc,CAAC;QAC/C,oBAAoB,EAAE,ufAAuf;QAC7gB,SAAS,EAAE,CAAC,oDAAoD,EAAE,+DAA+D,CAAC;QAClI,WAAW,EAAE,CAAC,4BAA4B,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,4BAA4B,CAAC;KAC3H;IAED,MAAM,EAAE;QACN,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,iDAAiD;QAC9D,aAAa,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,eAAe,CAAC;QACtD,oBAAoB,EAAE,qfAAqf;QAC3gB,SAAS,EAAE,CAAC,mDAAmD,EAAE,yCAAyC,CAAC;QAC3G,WAAW,EAAE,CAAC,8BAA8B,EAAE,iCAAiC,EAAE,0CAA0C,EAAE,wCAAwC,CAAC;KACvK;IAED,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,iDAAiD;QAC9D,aAAa,EAAE,CAAC,eAAe,CAAC;QAChC,oBAAoB,EAAE,gbAAgb;QACtc,SAAS,EAAE,CAAC,mDAAmD,EAAE,uCAAuC,CAAC;QACzG,WAAW,EAAE,CAAC,uBAAuB,EAAE,sCAAsC,EAAE,qCAAqC,EAAE,0CAA0C,CAAC;KAClK;IAED,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,gDAAgD;QAC7D,aAAa,EAAE,CAAC,sBAAsB,CAAC;QACvC,oBAAoB,EAAE,qaAAqa;QAC3b,SAAS,EAAE,CAAC,kDAAkD,EAAE,qDAAqD,CAAC;QACtH,WAAW,EAAE,CAAC,eAAe,EAAE,qCAAqC,EAAE,gCAAgC,EAAE,4CAA4C,CAAC;KACtJ;IAED,SAAS,EAAE;QACT,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,oDAAoD;QACjE,aAAa,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;QAClC,oBAAoB,EAAE,0fAA0f;QAChhB,SAAS,EAAE,CAAC,oDAAoD,EAAE,0CAA0C,CAAC;QAC7G,WAAW,EAAE,CAAC,mCAAmC,EAAE,mBAAmB,EAAE,gCAAgC,EAAE,sBAAsB,CAAC;KAClI;IAED,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,8CAA8C;QAC3D,aAAa,EAAE,CAAC,WAAW,EAAE,gBAAgB,CAAC;QAC9C,oBAAoB,EAAE,ijBAAijB;QACvkB,SAAS,EAAE,CAAC,+CAA+C,EAAE,8CAA8C,CAAC;QAC5G,WAAW,EAAE,CAAC,sBAAsB,EAAE,iCAAiC,EAAE,oCAAoC,EAAE,8CAA8C,CAAC;KAC/J;IAED,QAAQ,EAAE;QACR,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,uDAAuD;QACpE,aAAa,EAAE,CAAC,eAAe,EAAE,UAAU,CAAC;QAC5C,oBAAoB,EAAE,kgBAAkgB;QACxhB,SAAS,EAAE,CAAC,mDAAmD,EAAE,6DAA6D,CAAC;QAC/H,WAAW,EAAE,CAAC,wBAAwB,EAAE,mCAAmC,EAAE,oCAAoC,EAAE,0CAA0C,CAAC;KAC/J;IAED,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,gDAAgD;QAC7D,aAAa,EAAE,CAAC,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,CAAC;QACzF,oBAAoB,EAAE,+hBAA+hB;QACrjB,SAAS,EAAE,CAAC,4CAA4C,EAAE,6CAA6C,CAAC;QACxG,WAAW,EAAE,CAAC,oBAAoB,EAAE,eAAe,EAAE,oBAAoB,EAAE,iCAAiC,CAAC;KAC9G;CACF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAW;IACjD,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAW;IACnD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,MAAM;SACpB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,oBAAoB,EAAE,CAAC;SACpD,IAAI,CAAC,MAAM,CAAC,CAAC;IAChB,OAAO,2CAA2C,QAAQ,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,MAAM,MAAM,GACV,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC;IAC5C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,QAAQ,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAAgB,EAAE,GAAW;IACnE,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,wBAAwB,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kCAAkC;IAClC,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,YAAY,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,kBAAkB,eAAe,EAAE,EAAE,aAAa,CAAC,CAAC;IAExF,oBAAoB;IACpB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IAC1D,IAAI,SAAS,GAAa,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAClD,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,4BAA4B;IAC9B,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IACpF,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentConfig } from './types.js';
|
|
2
|
+
export declare function renameSymbol(symbolName: string, newName: string, cwd: string): Promise<{
|
|
3
|
+
filesChanged: string[];
|
|
4
|
+
occurrences: number;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function extractInterface(filePath: string, className: string, cwd: string): Promise<void>;
|
|
7
|
+
export declare function moveSymbol(symbolName: string, fromFile: string, toFile: string, cwd: string): Promise<void>;
|
|
8
|
+
export declare function splitFile(filePath: string, cwd: string, config: AgentConfig): Promise<void>;
|
|
9
|
+
export declare function runRefactor(action: 'rename' | 'extract' | 'move' | 'split', args: string[], config: AgentConfig): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=refactor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refactor.d.ts","sourceRoot":"","sources":["../src/refactor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK9C,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CA0B1D;AAID,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CAkCf;AAID,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CA8Df;AAID,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBjG;AAID,wBAAsB,WAAW,CAC/B,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,EAC/C,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CAuBf"}
|
package/dist/refactor.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { Project, SyntaxKind } from 'ts-morph';
|
|
4
|
+
import { runAgent } from './engine.js';
|
|
5
|
+
// ─── Rename Symbol ────────────────────────────────────────────────────────────
|
|
6
|
+
export async function renameSymbol(symbolName, newName, cwd) {
|
|
7
|
+
const project = new Project({ tsConfigFilePath: path.join(cwd, 'tsconfig.json') });
|
|
8
|
+
const changedFiles = new Set();
|
|
9
|
+
let occurrences = 0;
|
|
10
|
+
try {
|
|
11
|
+
for (const sourceFile of project.getSourceFiles()) {
|
|
12
|
+
const identifiers = sourceFile.getDescendantsOfKind(SyntaxKind.Identifier)
|
|
13
|
+
.filter(id => id.getText() === symbolName);
|
|
14
|
+
if (identifiers.length === 0)
|
|
15
|
+
continue;
|
|
16
|
+
occurrences += identifiers.length;
|
|
17
|
+
// rename all via the first node's rename (ts-morph propagates across project)
|
|
18
|
+
identifiers[0].rename(newName);
|
|
19
|
+
changedFiles.add(sourceFile.getFilePath());
|
|
20
|
+
}
|
|
21
|
+
await project.save();
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
throw new Error(`renameSymbol failed: ${err.message}`);
|
|
25
|
+
}
|
|
26
|
+
const filesChanged = Array.from(changedFiles);
|
|
27
|
+
console.log(chalk.green('✔') +
|
|
28
|
+
` Renamed "${symbolName}" → "${newName}" in ${filesChanged.length} files (${occurrences} occurrences)`);
|
|
29
|
+
return { filesChanged, occurrences };
|
|
30
|
+
}
|
|
31
|
+
// ─── Extract Interface ────────────────────────────────────────────────────────
|
|
32
|
+
export async function extractInterface(filePath, className, cwd) {
|
|
33
|
+
const project = new Project({ tsConfigFilePath: path.join(cwd, 'tsconfig.json') });
|
|
34
|
+
const absPath = path.isAbsolute(filePath) ? filePath : path.join(cwd, filePath);
|
|
35
|
+
try {
|
|
36
|
+
const sourceFile = project.getSourceFileOrThrow(absPath);
|
|
37
|
+
const classDecl = sourceFile.getClassOrThrow(className);
|
|
38
|
+
const methods = classDecl.getMethods().filter(m => m.getScope() === undefined || m.getScope() === 'public');
|
|
39
|
+
const signatures = methods.map(m => {
|
|
40
|
+
const params = m.getParameters().map(p => p.getText()).join(', ');
|
|
41
|
+
const returnType = m.getReturnTypeNode()?.getText() ?? 'void';
|
|
42
|
+
return ` ${m.getName()}(${params}): ${returnType};`;
|
|
43
|
+
});
|
|
44
|
+
const interfaceName = `${className}Interface`;
|
|
45
|
+
const interfaceContent = `export interface ${interfaceName} {\n${signatures.join('\n')}\n}\n`;
|
|
46
|
+
const dir = path.dirname(absPath);
|
|
47
|
+
const outPath = path.join(dir, `${interfaceName}.ts`);
|
|
48
|
+
const newFile = project.createSourceFile(outPath, interfaceContent, { overwrite: true });
|
|
49
|
+
await newFile.save();
|
|
50
|
+
// Add implements clause to the class
|
|
51
|
+
const relImport = `./${interfaceName}.js`;
|
|
52
|
+
sourceFile.addImportDeclaration({ namedImports: [interfaceName], moduleSpecifier: relImport });
|
|
53
|
+
classDecl.addImplements(interfaceName);
|
|
54
|
+
await sourceFile.save();
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
throw new Error(`extractInterface failed: ${err.message}`);
|
|
58
|
+
}
|
|
59
|
+
const relOut = path.relative(cwd, path.join(path.dirname(absPath), `${className}Interface.ts`));
|
|
60
|
+
console.log(chalk.green('✔') + ` Interface extracted: ${relOut}`);
|
|
61
|
+
}
|
|
62
|
+
// ─── Move Symbol ──────────────────────────────────────────────────────────────
|
|
63
|
+
export async function moveSymbol(symbolName, fromFile, toFile, cwd) {
|
|
64
|
+
const project = new Project({ tsConfigFilePath: path.join(cwd, 'tsconfig.json') });
|
|
65
|
+
const absFrom = path.isAbsolute(fromFile) ? fromFile : path.join(cwd, fromFile);
|
|
66
|
+
const absTo = path.isAbsolute(toFile) ? toFile : path.join(cwd, toFile);
|
|
67
|
+
try {
|
|
68
|
+
const src = project.getSourceFileOrThrow(absFrom);
|
|
69
|
+
// Locate the declaration (function, class, or variable statement)
|
|
70
|
+
const decl = src.getFunction(symbolName) ??
|
|
71
|
+
src.getClass(symbolName) ??
|
|
72
|
+
src.getVariableDeclaration(symbolName);
|
|
73
|
+
if (!decl)
|
|
74
|
+
throw new Error(`Symbol "${symbolName}" not found in ${fromFile}`);
|
|
75
|
+
const declText = decl.getText();
|
|
76
|
+
const isVariable = src.getVariableDeclaration(symbolName) !== undefined;
|
|
77
|
+
const exportedText = isVariable
|
|
78
|
+
? `export const ${declText};\n`
|
|
79
|
+
: declText.startsWith('export') ? `${declText}\n` : `export ${declText}\n`;
|
|
80
|
+
// Write to destination (create or append)
|
|
81
|
+
let dest = project.getSourceFile(absTo);
|
|
82
|
+
if (!dest) {
|
|
83
|
+
dest = project.createSourceFile(absTo, exportedText, { overwrite: false });
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
dest.addStatements(exportedText);
|
|
87
|
+
}
|
|
88
|
+
await dest.save();
|
|
89
|
+
// Remove original, add re-export
|
|
90
|
+
if (isVariable) {
|
|
91
|
+
src.getVariableStatement(symbolName)?.remove();
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
(src.getFunction(symbolName) ?? src.getClass(symbolName))?.remove();
|
|
95
|
+
}
|
|
96
|
+
const relToFrom = `./${path.relative(path.dirname(absFrom), absTo).replace(/\.ts$/, '.js')}`;
|
|
97
|
+
src.addExportDeclaration({ namedExports: [symbolName], moduleSpecifier: relToFrom });
|
|
98
|
+
await src.save();
|
|
99
|
+
// Update other files importing from fromFile
|
|
100
|
+
const relFromBase = `./${path.basename(absFrom, '.ts')}.js`;
|
|
101
|
+
for (const sf of project.getSourceFiles()) {
|
|
102
|
+
if (sf.getFilePath() === absFrom || sf.getFilePath() === absTo)
|
|
103
|
+
continue;
|
|
104
|
+
for (const imp of sf.getImportDeclarations()) {
|
|
105
|
+
if (imp.getModuleSpecifierValue().endsWith(relFromBase)) {
|
|
106
|
+
const named = imp.getNamedImports().find(n => n.getName() === symbolName);
|
|
107
|
+
if (!named)
|
|
108
|
+
continue;
|
|
109
|
+
named.remove();
|
|
110
|
+
const relToSf = `./${path.relative(path.dirname(sf.getFilePath()), absTo).replace(/\.ts$/, '.js')}`;
|
|
111
|
+
sf.addImportDeclaration({ namedImports: [symbolName], moduleSpecifier: relToSf });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
await sf.save();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
throw new Error(`moveSymbol failed: ${err.message}`);
|
|
119
|
+
}
|
|
120
|
+
const relFrom = path.relative(cwd, absFrom);
|
|
121
|
+
const relTo = path.relative(cwd, absTo);
|
|
122
|
+
console.log(chalk.green('✔') + ` Moved "${symbolName}" from ${relFrom} → ${relTo}`);
|
|
123
|
+
}
|
|
124
|
+
// ─── Split File ───────────────────────────────────────────────────────────────
|
|
125
|
+
export async function splitFile(filePath, cwd, config) {
|
|
126
|
+
const absPath = path.isAbsolute(filePath) ? filePath : path.join(cwd, filePath);
|
|
127
|
+
const { createReadStream } = await import('node:fs');
|
|
128
|
+
const { createInterface } = await import('node:readline');
|
|
129
|
+
let lineCount = 0;
|
|
130
|
+
await new Promise((resolve, reject) => {
|
|
131
|
+
const rl = createInterface({ input: createReadStream(absPath) });
|
|
132
|
+
rl.on('line', () => lineCount++);
|
|
133
|
+
rl.on('close', resolve);
|
|
134
|
+
rl.on('error', reject);
|
|
135
|
+
});
|
|
136
|
+
if (lineCount <= 200) {
|
|
137
|
+
console.log(chalk.yellow('⚠') + ` ${filePath} is ${lineCount} lines — no split needed (threshold: 200)`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
console.log(chalk.blue('ℹ') + ` Splitting ${filePath} (${lineCount} lines)…`);
|
|
141
|
+
const task = `Split ${filePath} into smaller focused modules. Each export group should go in its own file. ` +
|
|
142
|
+
`Update all imports. The original file should re-export everything for backward compatibility.`;
|
|
143
|
+
await runAgent(task, { ...config, cwd });
|
|
144
|
+
console.log(chalk.green('✔') + ` Split complete: ${filePath}`);
|
|
145
|
+
}
|
|
146
|
+
// ─── Dispatcher ───────────────────────────────────────────────────────────────
|
|
147
|
+
export async function runRefactor(action, args, config) {
|
|
148
|
+
const cwd = config.cwd;
|
|
149
|
+
switch (action) {
|
|
150
|
+
case 'rename':
|
|
151
|
+
if (args.length !== 2) {
|
|
152
|
+
console.error('Usage: refactor rename <oldName> <newName>');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
await renameSymbol(args[0], args[1], cwd);
|
|
156
|
+
break;
|
|
157
|
+
case 'extract':
|
|
158
|
+
if (args.length !== 2) {
|
|
159
|
+
console.error('Usage: refactor extract <filePath> <className>');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
await extractInterface(args[0], args[1], cwd);
|
|
163
|
+
break;
|
|
164
|
+
case 'move':
|
|
165
|
+
if (args.length !== 3) {
|
|
166
|
+
console.error('Usage: refactor move <symbolName> <fromFile> <toFile>');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
await moveSymbol(args[0], args[1], args[2], cwd);
|
|
170
|
+
break;
|
|
171
|
+
case 'split':
|
|
172
|
+
if (args.length !== 1) {
|
|
173
|
+
console.error('Usage: refactor split <filePath>');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
await splitFile(args[0], cwd, config);
|
|
177
|
+
break;
|
|
178
|
+
default:
|
|
179
|
+
console.error(`Unknown refactor action: ${action}. Valid: rename | extract | move | split`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=refactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refactor.js","sourceRoot":"","sources":["../src/refactor.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA4H9C,wBAAsB,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,SAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA2EvF"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
2
|
+
import { readdir, readFile } from 'fs/promises';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { execa } from 'execa';
|
|
8
|
+
const DEFAULT_PORT = 7799;
|
|
9
|
+
async function readSessions(cwd) {
|
|
10
|
+
const dir = path.join(cwd, '.koneck', 'sessions');
|
|
11
|
+
if (!existsSync(dir))
|
|
12
|
+
return [];
|
|
13
|
+
try {
|
|
14
|
+
const files = (await readdir(dir)).filter(f => f.endsWith('.jsonl')).sort().reverse().slice(0, 10);
|
|
15
|
+
const sessions = [];
|
|
16
|
+
for (const f of files) {
|
|
17
|
+
try {
|
|
18
|
+
const raw = await readFile(path.join(dir, f), 'utf8');
|
|
19
|
+
const firstLine = raw.split('\n')[0].trim();
|
|
20
|
+
if (firstLine)
|
|
21
|
+
sessions.push(JSON.parse(firstLine));
|
|
22
|
+
}
|
|
23
|
+
catch { /* skip malformed */ }
|
|
24
|
+
}
|
|
25
|
+
return sessions;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function buildDashboard(version) {
|
|
32
|
+
return `<!doctype html><html lang="en"><head>
|
|
33
|
+
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
34
|
+
<title>KONECK Dashboard</title>
|
|
35
|
+
<style>
|
|
36
|
+
*{box-sizing:border-box;margin:0;padding:0}
|
|
37
|
+
body{background:#0d1117;color:#c9d1d9;font-family:'Cascadia Code','Fira Code',monospace,ui-monospace;font-size:14px;line-height:1.6;padding:24px}
|
|
38
|
+
h1{color:#58a6ff;font-size:22px;margin-bottom:4px}
|
|
39
|
+
.sub{color:#8b949e;font-size:12px;margin-bottom:28px}
|
|
40
|
+
h2{color:#58a6ff;font-size:15px;border-bottom:1px solid #21262d;padding-bottom:6px;margin-bottom:14px}
|
|
41
|
+
section{margin-bottom:32px}
|
|
42
|
+
.card{background:#161b22;border:1px solid #21262d;border-radius:6px;padding:14px;margin-bottom:10px}
|
|
43
|
+
.card-title{color:#e6edf3;font-weight:bold;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
44
|
+
.meta{color:#8b949e;font-size:12px}
|
|
45
|
+
.meta span{margin-right:14px}
|
|
46
|
+
.badge{display:inline-block;background:#1f6feb33;color:#58a6ff;border:1px solid #1f6feb;border-radius:4px;font-size:11px;padding:1px 6px;margin-right:6px}
|
|
47
|
+
.health{background:#161b22;border:1px solid #21262d;border-radius:6px;padding:14px}
|
|
48
|
+
.health pre{white-space:pre-wrap;word-break:break-all;color:#7ee787;font-size:12px;max-height:260px;overflow-y:auto}
|
|
49
|
+
.hint{color:#8b949e;font-size:13px}
|
|
50
|
+
textarea{width:100%;background:#161b22;border:1px solid #30363d;border-radius:6px;color:#c9d1d9;font-family:inherit;font-size:13px;padding:10px;resize:vertical;min-height:80px}
|
|
51
|
+
textarea:focus{outline:none;border-color:#58a6ff}
|
|
52
|
+
button{background:#238636;border:none;border-radius:6px;color:#fff;cursor:pointer;font-family:inherit;font-size:13px;padding:8px 20px;margin-top:8px}
|
|
53
|
+
button:hover{background:#2ea043}
|
|
54
|
+
button:disabled{opacity:.5;cursor:not-allowed}
|
|
55
|
+
#output{background:#161b22;border:1px solid #21262d;border-radius:6px;padding:12px;margin-top:12px;display:none;max-height:320px;overflow-y:auto}
|
|
56
|
+
#output pre{white-space:pre-wrap;word-break:break-all;color:#7ee787;font-size:12px}
|
|
57
|
+
.empty{color:#8b949e;font-size:13px;padding:10px 0}
|
|
58
|
+
</style></head><body>
|
|
59
|
+
<h1>KONECK Dashboard</h1>
|
|
60
|
+
<div class="sub">v${version} — local agent dashboard</div>
|
|
61
|
+
|
|
62
|
+
<section>
|
|
63
|
+
<h2>Recent Sessions</h2>
|
|
64
|
+
<div id="sessions"><div class="empty">Loading…</div></div>
|
|
65
|
+
</section>
|
|
66
|
+
|
|
67
|
+
<section>
|
|
68
|
+
<h2>Repository Health</h2>
|
|
69
|
+
<div id="health"><div class="empty">Loading…</div></div>
|
|
70
|
+
</section>
|
|
71
|
+
|
|
72
|
+
<section>
|
|
73
|
+
<h2>Run Task</h2>
|
|
74
|
+
<textarea id="task" placeholder="Describe a task for KONECK…"></textarea><br>
|
|
75
|
+
<button id="run-btn" onclick="runTask()">Run Task</button>
|
|
76
|
+
<div id="output"><pre id="out-pre"></pre></div>
|
|
77
|
+
</section>
|
|
78
|
+
|
|
79
|
+
<script>
|
|
80
|
+
async function loadSessions(){
|
|
81
|
+
const r=await fetch('/api/sessions');
|
|
82
|
+
const data=await r.json();
|
|
83
|
+
const el=document.getElementById('sessions');
|
|
84
|
+
if(!data.length){el.innerHTML='<div class="empty">No sessions yet. Run a task to get started.</div>';return;}
|
|
85
|
+
el.innerHTML=data.map(s=>{
|
|
86
|
+
const cost=s.totalTokens?(s.totalTokens/1e6*3).toFixed(4):'?';
|
|
87
|
+
const d=new Date(s.startedAt).toLocaleString();
|
|
88
|
+
return \`<div class="card">
|
|
89
|
+
<div class="card-title">\${s.task||'(no task)'}</div>
|
|
90
|
+
<div class="meta">
|
|
91
|
+
<span class="badge">\${s.model}</span>
|
|
92
|
+
<span>\${d}</span>
|
|
93
|
+
<span>\${s.turns} turns</span>
|
|
94
|
+
<span>\${(s.totalTokens||0).toLocaleString()} tokens</span>
|
|
95
|
+
<span>~\$\${cost}</span>
|
|
96
|
+
</div></div>\`;
|
|
97
|
+
}).join('');
|
|
98
|
+
}
|
|
99
|
+
async function loadHealth(){
|
|
100
|
+
const r=await fetch('/api/health');
|
|
101
|
+
const data=await r.json();
|
|
102
|
+
const el=document.getElementById('health');
|
|
103
|
+
if(data.status==='not-run'){
|
|
104
|
+
el.innerHTML='<div class="health"><span class="hint">Run <code>koneck health</code> to generate a health report.</span></div>';
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
el.innerHTML=\`<div class="health"><pre>\${JSON.stringify(data,null,2)}</pre></div>\`;
|
|
108
|
+
}
|
|
109
|
+
function runTask(){
|
|
110
|
+
const task=document.getElementById('task').value.trim();
|
|
111
|
+
if(!task)return;
|
|
112
|
+
const btn=document.getElementById('run-btn');
|
|
113
|
+
const outDiv=document.getElementById('output');
|
|
114
|
+
const pre=document.getElementById('out-pre');
|
|
115
|
+
btn.disabled=true;pre.textContent='';outDiv.style.display='block';
|
|
116
|
+
const es=new EventSource('/run?task='+encodeURIComponent(task));
|
|
117
|
+
es.onmessage=e=>{
|
|
118
|
+
if(e.data==='[DONE]'){es.close();btn.disabled=false;return;}
|
|
119
|
+
pre.textContent+=e.data+'\\n';
|
|
120
|
+
outDiv.scrollTop=outDiv.scrollHeight;
|
|
121
|
+
};
|
|
122
|
+
es.onerror=()=>{es.close();btn.disabled=false;};
|
|
123
|
+
}
|
|
124
|
+
loadSessions();loadHealth();
|
|
125
|
+
</script></body></html>`;
|
|
126
|
+
}
|
|
127
|
+
function send(res, status, body, ct = 'text/plain') {
|
|
128
|
+
res.writeHead(status, { 'Content-Type': ct });
|
|
129
|
+
res.end(body);
|
|
130
|
+
}
|
|
131
|
+
export async function runServer(config, port = DEFAULT_PORT) {
|
|
132
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
133
|
+
const __dirname = path.dirname(__filename);
|
|
134
|
+
const distIndexPath = path.join(__dirname, 'index.js');
|
|
135
|
+
// read version once
|
|
136
|
+
let version = '2.x';
|
|
137
|
+
try {
|
|
138
|
+
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
139
|
+
const pkg = JSON.parse(await readFile(pkgPath, 'utf8'));
|
|
140
|
+
version = pkg.version;
|
|
141
|
+
}
|
|
142
|
+
catch { /* ignore */ }
|
|
143
|
+
const dashboard = buildDashboard(version);
|
|
144
|
+
const server = createServer(async (req, res) => {
|
|
145
|
+
const url = new URL(req.url ?? '/', `http://localhost:${port}`);
|
|
146
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
147
|
+
// GET /
|
|
148
|
+
if (req.method === 'GET' && url.pathname === '/') {
|
|
149
|
+
return send(res, 200, dashboard, 'text/html; charset=utf-8');
|
|
150
|
+
}
|
|
151
|
+
// GET /api/sessions
|
|
152
|
+
if (req.method === 'GET' && url.pathname === '/api/sessions') {
|
|
153
|
+
const sessions = await readSessions(config.cwd);
|
|
154
|
+
return send(res, 200, JSON.stringify(sessions), 'application/json');
|
|
155
|
+
}
|
|
156
|
+
// GET /api/health
|
|
157
|
+
if (req.method === 'GET' && url.pathname === '/api/health') {
|
|
158
|
+
const hPath = path.join(config.cwd, '.koneck', 'health-report.json');
|
|
159
|
+
if (!existsSync(hPath))
|
|
160
|
+
return send(res, 200, JSON.stringify({ status: 'not-run' }), 'application/json');
|
|
161
|
+
try {
|
|
162
|
+
const raw = await readFile(hPath, 'utf8');
|
|
163
|
+
return send(res, 200, raw, 'application/json');
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
return send(res, 200, JSON.stringify({ status: 'not-run' }), 'application/json');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// /run — GET ?task=… (EventSource) or POST { task } (direct API)
|
|
170
|
+
if (url.pathname === '/run' && (req.method === 'GET' || req.method === 'POST')) {
|
|
171
|
+
let task = url.searchParams.get('task') ?? '';
|
|
172
|
+
if (req.method === 'POST') {
|
|
173
|
+
const chunks = [];
|
|
174
|
+
for await (const chunk of req)
|
|
175
|
+
chunks.push(chunk);
|
|
176
|
+
try {
|
|
177
|
+
({ task } = JSON.parse(Buffer.concat(chunks).toString()));
|
|
178
|
+
}
|
|
179
|
+
catch { /* ignore */ }
|
|
180
|
+
}
|
|
181
|
+
if (!task)
|
|
182
|
+
return send(res, 400, 'task required');
|
|
183
|
+
res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });
|
|
184
|
+
const proc = execa('node', [distIndexPath, task], {
|
|
185
|
+
all: true, reject: false, cwd: config.cwd,
|
|
186
|
+
env: { ...process.env, KONECK_CI: '1' },
|
|
187
|
+
});
|
|
188
|
+
proc.all?.on('data', (chunk) => {
|
|
189
|
+
for (const line of chunk.toString().split('\n')) {
|
|
190
|
+
if (line)
|
|
191
|
+
res.write(`data: ${line}\n\n`);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
await proc;
|
|
195
|
+
res.write('data: [DONE]\n\n');
|
|
196
|
+
res.end();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
send(res, 404, 'Not found');
|
|
200
|
+
});
|
|
201
|
+
await new Promise((resolve, reject) => {
|
|
202
|
+
server.listen(port, () => {
|
|
203
|
+
console.log(chalk.cyan(` KONECK dashboard → http://localhost:${port}\n`));
|
|
204
|
+
});
|
|
205
|
+
server.on('error', reject);
|
|
206
|
+
process.on('SIGINT', () => { server.close(); resolve(); process.exit(0); });
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-gen.d.ts","sourceRoot":"","sources":["../src/test-gen.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAQ9C,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoHxF"}
|