@kkelly-offical/kkcode 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.
Files changed (196) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +445 -0
  3. package/package.json +46 -0
  4. package/src/agent/agent.mjs +170 -0
  5. package/src/agent/custom-agent-loader.mjs +158 -0
  6. package/src/agent/generator.mjs +115 -0
  7. package/src/agent/prompt/architect.txt +36 -0
  8. package/src/agent/prompt/build-fixer.txt +71 -0
  9. package/src/agent/prompt/build.txt +101 -0
  10. package/src/agent/prompt/compaction.txt +12 -0
  11. package/src/agent/prompt/explore.txt +29 -0
  12. package/src/agent/prompt/guide.txt +40 -0
  13. package/src/agent/prompt/longagent.txt +178 -0
  14. package/src/agent/prompt/plan.txt +50 -0
  15. package/src/agent/prompt/researcher.txt +23 -0
  16. package/src/agent/prompt/reviewer.txt +44 -0
  17. package/src/agent/prompt/security-reviewer.txt +62 -0
  18. package/src/agent/prompt/tdd-guide.txt +84 -0
  19. package/src/agent/prompt/title.txt +8 -0
  20. package/src/command/custom-commands.mjs +57 -0
  21. package/src/commands/agent.mjs +71 -0
  22. package/src/commands/audit.mjs +77 -0
  23. package/src/commands/background.mjs +86 -0
  24. package/src/commands/chat.mjs +114 -0
  25. package/src/commands/command.mjs +41 -0
  26. package/src/commands/config.mjs +44 -0
  27. package/src/commands/doctor.mjs +148 -0
  28. package/src/commands/hook.mjs +29 -0
  29. package/src/commands/init.mjs +141 -0
  30. package/src/commands/longagent.mjs +100 -0
  31. package/src/commands/mcp.mjs +89 -0
  32. package/src/commands/permission.mjs +36 -0
  33. package/src/commands/prompt.mjs +42 -0
  34. package/src/commands/review.mjs +266 -0
  35. package/src/commands/rule.mjs +34 -0
  36. package/src/commands/session.mjs +235 -0
  37. package/src/commands/theme.mjs +98 -0
  38. package/src/commands/usage.mjs +91 -0
  39. package/src/config/defaults.mjs +195 -0
  40. package/src/config/import-config.mjs +76 -0
  41. package/src/config/load-config.mjs +76 -0
  42. package/src/config/schema.mjs +509 -0
  43. package/src/context.mjs +40 -0
  44. package/src/core/constants.mjs +46 -0
  45. package/src/core/errors.mjs +57 -0
  46. package/src/core/events.mjs +29 -0
  47. package/src/core/types.mjs +57 -0
  48. package/src/github/api.mjs +78 -0
  49. package/src/github/auth.mjs +286 -0
  50. package/src/github/flow.mjs +298 -0
  51. package/src/github/workspace.mjs +212 -0
  52. package/src/index.mjs +82 -0
  53. package/src/knowledge/api-design.txt +9 -0
  54. package/src/knowledge/cpp.txt +10 -0
  55. package/src/knowledge/docker.txt +10 -0
  56. package/src/knowledge/dotnet.txt +9 -0
  57. package/src/knowledge/electron.txt +10 -0
  58. package/src/knowledge/flutter.txt +10 -0
  59. package/src/knowledge/go.txt +9 -0
  60. package/src/knowledge/graphql.txt +10 -0
  61. package/src/knowledge/java.txt +9 -0
  62. package/src/knowledge/kotlin.txt +10 -0
  63. package/src/knowledge/loader.mjs +125 -0
  64. package/src/knowledge/next.txt +8 -0
  65. package/src/knowledge/node.txt +8 -0
  66. package/src/knowledge/nuxt.txt +9 -0
  67. package/src/knowledge/php.txt +10 -0
  68. package/src/knowledge/python.txt +10 -0
  69. package/src/knowledge/react-native.txt +10 -0
  70. package/src/knowledge/react.txt +9 -0
  71. package/src/knowledge/ruby.txt +11 -0
  72. package/src/knowledge/rust.txt +9 -0
  73. package/src/knowledge/svelte.txt +9 -0
  74. package/src/knowledge/swift.txt +10 -0
  75. package/src/knowledge/tailwind.txt +10 -0
  76. package/src/knowledge/testing.txt +8 -0
  77. package/src/knowledge/typescript.txt +8 -0
  78. package/src/knowledge/vue.txt +9 -0
  79. package/src/mcp/client-http.mjs +157 -0
  80. package/src/mcp/client-sse.mjs +286 -0
  81. package/src/mcp/client-stdio.mjs +451 -0
  82. package/src/mcp/registry.mjs +394 -0
  83. package/src/mcp/stdio-framing.mjs +127 -0
  84. package/src/orchestration/background-manager.mjs +358 -0
  85. package/src/orchestration/background-worker.mjs +245 -0
  86. package/src/orchestration/longagent-manager.mjs +116 -0
  87. package/src/orchestration/stage-scheduler.mjs +489 -0
  88. package/src/orchestration/subagent-router.mjs +62 -0
  89. package/src/orchestration/task-scheduler.mjs +74 -0
  90. package/src/permission/engine.mjs +92 -0
  91. package/src/permission/exec-policy.mjs +372 -0
  92. package/src/permission/prompt.mjs +39 -0
  93. package/src/permission/rules.mjs +120 -0
  94. package/src/permission/workspace-trust.mjs +44 -0
  95. package/src/plugin/builtin-hooks/console-warn.mjs +41 -0
  96. package/src/plugin/builtin-hooks/extract-patterns.mjs +75 -0
  97. package/src/plugin/builtin-hooks/post-edit-format.mjs +57 -0
  98. package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +61 -0
  99. package/src/plugin/builtin-hooks/strategic-compaction.mjs +38 -0
  100. package/src/plugin/hook-bus.mjs +154 -0
  101. package/src/provider/anthropic.mjs +389 -0
  102. package/src/provider/ollama.mjs +236 -0
  103. package/src/provider/openai-compatible.mjs +1 -0
  104. package/src/provider/openai.mjs +339 -0
  105. package/src/provider/retry-policy.mjs +68 -0
  106. package/src/provider/router.mjs +228 -0
  107. package/src/provider/sse.mjs +91 -0
  108. package/src/repl.mjs +2929 -0
  109. package/src/review/diff-parser.mjs +36 -0
  110. package/src/review/rejection-queue.mjs +62 -0
  111. package/src/review/review-store.mjs +21 -0
  112. package/src/review/risk-score.mjs +61 -0
  113. package/src/rules/load-rules.mjs +64 -0
  114. package/src/runtime.mjs +1 -0
  115. package/src/session/checkpoint.mjs +239 -0
  116. package/src/session/compaction.mjs +276 -0
  117. package/src/session/engine.mjs +225 -0
  118. package/src/session/instinct-manager.mjs +172 -0
  119. package/src/session/instruction-loader.mjs +25 -0
  120. package/src/session/longagent-plan.mjs +329 -0
  121. package/src/session/longagent-scaffold.mjs +100 -0
  122. package/src/session/longagent.mjs +1462 -0
  123. package/src/session/loop.mjs +905 -0
  124. package/src/session/memory-loader.mjs +75 -0
  125. package/src/session/project-context.mjs +367 -0
  126. package/src/session/prompt/anthropic.txt +151 -0
  127. package/src/session/prompt/beast.txt +37 -0
  128. package/src/session/prompt/max-steps.txt +6 -0
  129. package/src/session/prompt/plan.txt +9 -0
  130. package/src/session/prompt/qwen.txt +46 -0
  131. package/src/session/prompt-loader.mjs +18 -0
  132. package/src/session/recovery.mjs +52 -0
  133. package/src/session/store.mjs +503 -0
  134. package/src/session/system-prompt.mjs +260 -0
  135. package/src/session/task-validator.mjs +266 -0
  136. package/src/session/usability-gates.mjs +379 -0
  137. package/src/skill/builtin/backend-patterns.mjs +123 -0
  138. package/src/skill/builtin/commit.mjs +64 -0
  139. package/src/skill/builtin/debug.mjs +45 -0
  140. package/src/skill/builtin/frontend-patterns.mjs +120 -0
  141. package/src/skill/builtin/frontend.mjs +188 -0
  142. package/src/skill/builtin/init.mjs +220 -0
  143. package/src/skill/builtin/review.mjs +49 -0
  144. package/src/skill/builtin/security-checklist.mjs +80 -0
  145. package/src/skill/builtin/tdd.mjs +54 -0
  146. package/src/skill/generator.mjs +113 -0
  147. package/src/skill/registry.mjs +336 -0
  148. package/src/storage/audit-store.mjs +83 -0
  149. package/src/storage/event-log.mjs +82 -0
  150. package/src/storage/ghost-commit-store.mjs +235 -0
  151. package/src/storage/json-store.mjs +53 -0
  152. package/src/storage/paths.mjs +148 -0
  153. package/src/theme/color.mjs +64 -0
  154. package/src/theme/default-theme.mjs +29 -0
  155. package/src/theme/load-theme.mjs +71 -0
  156. package/src/theme/markdown.mjs +135 -0
  157. package/src/theme/schema.mjs +45 -0
  158. package/src/theme/status-bar.mjs +158 -0
  159. package/src/tool/audit-wrapper.mjs +38 -0
  160. package/src/tool/edit-transaction.mjs +126 -0
  161. package/src/tool/executor.mjs +109 -0
  162. package/src/tool/file-lock-manager.mjs +85 -0
  163. package/src/tool/git-auto.mjs +545 -0
  164. package/src/tool/git-full-auto.mjs +478 -0
  165. package/src/tool/image-util.mjs +276 -0
  166. package/src/tool/prompt/background_cancel.txt +1 -0
  167. package/src/tool/prompt/background_output.txt +1 -0
  168. package/src/tool/prompt/bash.txt +71 -0
  169. package/src/tool/prompt/codesearch.txt +18 -0
  170. package/src/tool/prompt/edit.txt +27 -0
  171. package/src/tool/prompt/enter_plan.txt +74 -0
  172. package/src/tool/prompt/exit_plan.txt +62 -0
  173. package/src/tool/prompt/glob.txt +33 -0
  174. package/src/tool/prompt/grep.txt +43 -0
  175. package/src/tool/prompt/list.txt +8 -0
  176. package/src/tool/prompt/multiedit.txt +20 -0
  177. package/src/tool/prompt/notebookedit.txt +21 -0
  178. package/src/tool/prompt/patch.txt +24 -0
  179. package/src/tool/prompt/question.txt +44 -0
  180. package/src/tool/prompt/read.txt +40 -0
  181. package/src/tool/prompt/task.txt +83 -0
  182. package/src/tool/prompt/todowrite.txt +117 -0
  183. package/src/tool/prompt/webfetch.txt +38 -0
  184. package/src/tool/prompt/websearch.txt +43 -0
  185. package/src/tool/prompt/write.txt +38 -0
  186. package/src/tool/prompt-loader.mjs +18 -0
  187. package/src/tool/question-prompt.mjs +86 -0
  188. package/src/tool/registry.mjs +1309 -0
  189. package/src/tool/task-tool.mjs +28 -0
  190. package/src/ui/activity-renderer.mjs +410 -0
  191. package/src/ui/repl-dashboard.mjs +357 -0
  192. package/src/usage/pricing.mjs +121 -0
  193. package/src/usage/usage-meter.mjs +113 -0
  194. package/src/util/git.mjs +496 -0
  195. package/src/util/template.mjs +10 -0
  196. package/src/util/yaml.mjs +100 -0
@@ -0,0 +1,9 @@
1
+ Java / Spring Boot conventions for this project:
2
+ - Spring Boot with @SpringBootApplication entry point
3
+ - @RestController for API endpoints, @Service for business logic
4
+ - @Repository with Spring Data JPA for data access
5
+ - Constructor injection (not field injection) for dependencies
6
+ - Records for DTOs, entities with @Entity annotation
7
+ - Validation: @Valid + jakarta.validation annotations
8
+ - Testing: JUnit 5 + Mockito, @SpringBootTest for integration
9
+ - Maven or Gradle for build, application.yml for config
@@ -0,0 +1,10 @@
1
+ Kotlin conventions for this project:
2
+ - Null safety: use ?, ?., ?:, let, require, check
3
+ - Data classes for DTOs and value objects
4
+ - Sealed classes for restricted hierarchies and state machines
5
+ - Coroutines: suspend functions, Flow for reactive streams
6
+ - Extension functions for utility methods
7
+ - Scope functions: let, run, with, apply, also
8
+ - Android: Jetpack Compose for UI, ViewModel + StateFlow for state
9
+ - Spring Boot: @RestController, @Service with constructor injection
10
+ - Testing: JUnit 5 + MockK, kotlinx-coroutines-test for coroutines
@@ -0,0 +1,125 @@
1
+ import { readFile } from "node:fs/promises"
2
+ import path from "node:path"
3
+ import { fileURLToPath } from "node:url"
4
+
5
+ const KNOWLEDGE_DIR = path.dirname(fileURLToPath(import.meta.url))
6
+ const cache = new Map()
7
+
8
+ // Framework → knowledge files mapping
9
+ const FRAMEWORK_MAP = {
10
+ vue: ["vue.txt"],
11
+ react: ["react.txt"],
12
+ next: ["next.txt", "react.txt"],
13
+ nuxt: ["nuxt.txt", "vue.txt"],
14
+ sveltekit: ["svelte.txt"],
15
+ svelte: ["svelte.txt"],
16
+ angular: [],
17
+ astro: [],
18
+ solid: [],
19
+ "react-native": ["react-native.txt", "react.txt"],
20
+ electron: ["electron.txt"],
21
+ flutter: ["flutter.txt"],
22
+ laravel: ["php.txt"],
23
+ rails: ["ruby.txt"],
24
+ }
25
+
26
+ // Backend frameworks → language knowledge
27
+ const BACKEND_FRAMEWORK_LANG = {
28
+ fastapi: "python.txt",
29
+ django: "python.txt",
30
+ flask: "python.txt",
31
+ gin: "go.txt",
32
+ fiber: "go.txt",
33
+ echo: "go.txt",
34
+ actix: "rust.txt",
35
+ axum: "rust.txt",
36
+ rocket: "rust.txt",
37
+ spring: "java.txt",
38
+ aspnet: "dotnet.txt",
39
+ laravel: "php.txt",
40
+ rails: "ruby.txt",
41
+ }
42
+
43
+ // Language → knowledge file (for non-JS ecosystems)
44
+ const LANGUAGE_MAP = {
45
+ go: "go.txt",
46
+ python: "python.txt",
47
+ rust: "rust.txt",
48
+ java: "java.txt",
49
+ kotlin: "kotlin.txt",
50
+ php: "php.txt",
51
+ ruby: "ruby.txt",
52
+ dart: "flutter.txt",
53
+ swift: "swift.txt",
54
+ cpp: "cpp.txt",
55
+ dotnet: "dotnet.txt",
56
+ }
57
+
58
+ // Project type → scenario knowledge
59
+ const TYPE_MAP = {
60
+ backend: ["api-design.txt"],
61
+ fullstack: ["api-design.txt"],
62
+ }
63
+
64
+ // Feature → knowledge file
65
+ const FEATURE_MAP = {
66
+ tailwind: "tailwind.txt",
67
+ graphql: "graphql.txt",
68
+ docker: "docker.txt",
69
+ electron: "electron.txt",
70
+ "react-native": "react-native.txt",
71
+ }
72
+
73
+ /**
74
+ * Load knowledge files matching the detected project context.
75
+ * Returns concatenated knowledge text, or empty string.
76
+ */
77
+ export async function loadKnowledge({ framework, language, projectType, hasTests, features = [] }) {
78
+ const files = new Set()
79
+
80
+ // Tier 1: Framework knowledge
81
+ if (framework) {
82
+ for (const f of (FRAMEWORK_MAP[framework] || [])) files.add(f)
83
+ // Backend framework → language file
84
+ if (BACKEND_FRAMEWORK_LANG[framework]) files.add(BACKEND_FRAMEWORK_LANG[framework])
85
+ }
86
+
87
+ // Tier 1: Language knowledge
88
+ if (language === "typescript") files.add("typescript.txt")
89
+ if (!framework && language === "javascript") files.add("node.txt")
90
+ // Non-JS languages
91
+ if (LANGUAGE_MAP[language] && !files.has(LANGUAGE_MAP[language])) {
92
+ files.add(LANGUAGE_MAP[language])
93
+ }
94
+
95
+ // Tier 2: Scenario knowledge
96
+ if (projectType && TYPE_MAP[projectType]) {
97
+ for (const f of TYPE_MAP[projectType]) files.add(f)
98
+ }
99
+ if (hasTests) files.add("testing.txt")
100
+
101
+ // Tier 2: Feature knowledge
102
+ for (const feat of features) {
103
+ if (FEATURE_MAP[feat]) files.add(FEATURE_MAP[feat])
104
+ }
105
+
106
+ // Load and concatenate
107
+ const sections = []
108
+ for (const file of files) {
109
+ const text = await loadFile(file)
110
+ if (text) sections.push(text)
111
+ }
112
+ return sections.length ? sections.join("\n\n") : ""
113
+ }
114
+
115
+ async function loadFile(name) {
116
+ if (cache.has(name)) return cache.get(name)
117
+ try {
118
+ const text = (await readFile(path.join(KNOWLEDGE_DIR, name), "utf8")).trim()
119
+ cache.set(name, text)
120
+ return text
121
+ } catch {
122
+ cache.set(name, "")
123
+ return ""
124
+ }
125
+ }
@@ -0,0 +1,8 @@
1
+ Next.js App Router conventions:
2
+ - Server Components by default, 'use client' only for interactivity
3
+ - app/ directory: layout.tsx, page.tsx, loading.tsx, error.tsx
4
+ - Server Actions with 'use server' for mutations
5
+ - Data fetching: async Server Components, no useEffect for data
6
+ - next/image for images, next/link for navigation, next/font for fonts
7
+ - Route Handlers in app/api/ for API endpoints
8
+ - Metadata API for SEO: export const metadata or generateMetadata()
@@ -0,0 +1,8 @@
1
+ Node.js conventions for this project:
2
+ - ESM modules ("type": "module" in package.json)
3
+ - Async/await for all I/O, avoid callback patterns
4
+ - Error handling: try/catch with specific error types
5
+ - Environment: dotenv for config, never hardcode secrets
6
+ - Logging: structured logging (pino or winston)
7
+ - Validation: zod or joi for input validation
8
+ - File structure: src/ with clear separation of concerns
@@ -0,0 +1,9 @@
1
+ Nuxt 3 conventions for this project:
2
+ - Auto-imports: no need to import ref, computed, useState, etc.
3
+ - Pages auto-register routes based on file structure (pages/)
4
+ - Components auto-register based on file name (components/)
5
+ - Composables auto-imported from composables/ directory
6
+ - useFetch() or useAsyncData() for SSR-friendly data fetching
7
+ - definePageMeta() for page-level metadata and middleware
8
+ - server/api/ for API routes with defineEventHandler()
9
+ - useState('key', () => default) for SSR-safe shared state
@@ -0,0 +1,10 @@
1
+ PHP/Laravel conventions for this project:
2
+ - MVC architecture: Controllers, Models (Eloquent), Blade views
3
+ - Routing: routes/web.php for web, routes/api.php for API
4
+ - Eloquent ORM: relationships, scopes, accessors/mutators
5
+ - Migrations for database schema, Seeders for test data
6
+ - Form Requests for validation, Resources for API responses
7
+ - Middleware for authentication, CORS, rate limiting
8
+ - Artisan commands: php artisan make:model/controller/migration
9
+ - Composer for dependency management
10
+ - Testing: PHPUnit with Feature and Unit test directories
@@ -0,0 +1,10 @@
1
+ Python conventions for this project:
2
+ - Type hints on all function signatures
3
+ - Pydantic models for data validation and serialization
4
+ - async/await for I/O-bound operations
5
+ - Virtual environment (venv or poetry)
6
+ - Project structure: src/<package>/ with __init__.py
7
+ - Testing: pytest with fixtures, parametrize for variants
8
+ - Linting: ruff for formatting and linting
9
+ - Logging: use logging module, not print()
10
+ - Error handling: specific exceptions, not bare except
@@ -0,0 +1,10 @@
1
+ React Native conventions for this project:
2
+ - Functional components with hooks, same as React
3
+ - Navigation: React Navigation (@react-navigation/native)
4
+ - Styling: StyleSheet.create(), flexbox layout (default column)
5
+ - Platform-specific: Platform.OS, Platform.select(), .ios.tsx/.android.tsx
6
+ - Native modules: use Expo SDK or react-native-* community packages
7
+ - State: React Context, Zustand, or Redux Toolkit
8
+ - Lists: FlatList for long lists (not ScrollView + map)
9
+ - Images: require() for local, { uri } for remote, use caching
10
+ - Testing: Jest + React Native Testing Library
@@ -0,0 +1,9 @@
1
+ React conventions for this project:
2
+ - Functional components only, TypeScript interfaces for props
3
+ - Hooks: useState, useEffect, useMemo, useCallback, useRef
4
+ - Custom hooks in hooks/ directory, prefixed with "use"
5
+ - React Router v6: createBrowserRouter, useParams, useNavigate
6
+ - State: local useState, complex useReducer, global Context/Zustand
7
+ - Prefer named exports, one component per file
8
+ - Memoize expensive components with React.memo()
9
+ - Error boundaries for fault isolation
@@ -0,0 +1,11 @@
1
+ Ruby/Rails conventions for this project:
2
+ - MVC: app/controllers/, app/models/, app/views/
3
+ - Convention over configuration: naming drives behavior
4
+ - ActiveRecord for ORM: migrations, associations, validations, scopes
5
+ - RESTful routes: resources :users in config/routes.rb
6
+ - Strong parameters for mass assignment protection
7
+ - Concerns for shared model/controller logic
8
+ - Background jobs: Sidekiq or ActiveJob
9
+ - Testing: RSpec preferred, FactoryBot for test data
10
+ - Gems via Bundler, Gemfile for dependency management
11
+ - Ruby style: snake_case methods, 2-space indent, no semicolons
@@ -0,0 +1,9 @@
1
+ Rust conventions for this project:
2
+ - Ownership and borrowing: prefer references over cloning
3
+ - Error handling: Result<T, E> with ? operator, thiserror for custom errors
4
+ - Traits for abstraction, impl blocks for methods
5
+ - Pattern matching with match and if let
6
+ - Cargo workspace for multi-crate projects
7
+ - Testing: #[cfg(test)] mod tests, #[test] functions
8
+ - Naming: snake_case for functions/variables, PascalCase for types
9
+ - Use clippy lints and rustfmt for code quality
@@ -0,0 +1,9 @@
1
+ SvelteKit conventions for this project:
2
+ - Svelte 5 runes: $state(), $derived(), $effect(), $props()
3
+ - File-based routing: src/routes/+page.svelte, +layout.svelte
4
+ - Server data loading: +page.server.ts with export const load
5
+ - Access data in page: let { data } = $props()
6
+ - <style> is scoped by default in Svelte components
7
+ - Form actions for mutations: +page.server.ts export const actions
8
+ - $lib alias for src/lib/ imports
9
+ - Use <script lang="ts"> for TypeScript
@@ -0,0 +1,10 @@
1
+ Swift conventions for this project:
2
+ - SwiftUI: declarative UI with @State, @Binding, @ObservedObject, @EnvironmentObject
3
+ - MVVM architecture: View, ViewModel (ObservableObject), Model
4
+ - Combine framework for reactive programming
5
+ - Structured concurrency: async/await, Task, AsyncSequence
6
+ - Protocol-oriented programming over class inheritance
7
+ - Optionals: guard let, if let, nil coalescing (??)
8
+ - SPM (Swift Package Manager) for dependencies
9
+ - Naming: camelCase for properties/methods, PascalCase for types
10
+ - Testing: XCTest framework, XCTAssert for assertions
@@ -0,0 +1,10 @@
1
+ Tailwind CSS conventions:
2
+ - Utility-first: compose styles with utility classes, avoid custom CSS
3
+ - Responsive: mobile-first with sm:, md:, lg:, xl:, 2xl: prefixes
4
+ - Dark mode: dark: prefix with class or media strategy
5
+ - Component patterns: extract repeated patterns with @apply in CSS or component abstraction
6
+ - Spacing scale: p-4 = 1rem, m-2 = 0.5rem (4px base)
7
+ - Colors: bg-blue-500, text-gray-900, use project's color palette
8
+ - Layout: flex, grid, container mx-auto, gap utilities
9
+ - Customization: tailwind.config.js for theme extension
10
+ - Avoid: inline styles, arbitrary values when a utility exists
@@ -0,0 +1,8 @@
1
+ Testing conventions:
2
+ - Test file next to source or in __tests__/ directory
3
+ - Name: [module].test.ts / test_[module].py / [module]_test.go
4
+ - Structure: Arrange-Act-Assert (AAA) pattern
5
+ - Cover: happy path, edge cases, error conditions
6
+ - Mock external dependencies, not internal logic
7
+ - Integration tests for API endpoints and database queries
8
+ - Avoid testing implementation details, test behavior
@@ -0,0 +1,8 @@
1
+ TypeScript conventions:
2
+ - Strict mode enabled (strict: true in tsconfig)
3
+ - Prefer interfaces over type aliases for object shapes
4
+ - Use discriminated unions for state machines
5
+ - Avoid 'any', use 'unknown' + type guards instead
6
+ - Utility types: Partial<T>, Pick<T,K>, Omit<T,K>, Record<K,V>
7
+ - Enums: prefer const enums or string literal unions
8
+ - Generic constraints: <T extends Base> for bounded generics
@@ -0,0 +1,9 @@
1
+ Vue 3 conventions for this project:
2
+ - Single-file components with <script setup lang="ts">
3
+ - Composition API: ref(), reactive(), computed(), watch()
4
+ - Props: defineProps<T>(), Emits: defineEmits<T>()
5
+ - Pinia stores with setup syntax: defineStore('name', () => { ... })
6
+ - Vue Router: createRouter + createWebHistory, lazy routes
7
+ - <style scoped> by default, CSS variables for theming
8
+ - Component naming: PascalCase files, kebab-case in templates
9
+ - Composables in composables/ directory, prefixed with "use"
@@ -0,0 +1,157 @@
1
+ import { McpError } from "../core/errors.mjs"
2
+ import { EventBus } from "../core/events.mjs"
3
+ import { EVENT_TYPES } from "../core/constants.mjs"
4
+
5
+ function timeoutSignal(ms, parentSignal = null) {
6
+ const own = AbortSignal.timeout(ms)
7
+ if (!parentSignal) return own
8
+ return AbortSignal.any([parentSignal, own])
9
+ }
10
+
11
+ function classifyHttpError(error, status = null) {
12
+ const msg = String(error?.message || error || "")
13
+ if (msg.includes("AbortError") || msg.includes("timeout") || msg.includes("abort")) return "timeout"
14
+ if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed")) return "connection_refused"
15
+ if (status && status >= 500) return "server_crash"
16
+ if (status && status >= 400) return "bad_response"
17
+ return "unknown"
18
+ }
19
+
20
+ function normalizeToolResult(result, serverName, toolName) {
21
+ if (result?.isError) {
22
+ const text = Array.isArray(result.content)
23
+ ? result.content.map((item) => item?.text || "").join("\n").trim()
24
+ : ""
25
+ throw new McpError(text || "mcp tool returned isError", {
26
+ reason: "bad_response",
27
+ server: serverName,
28
+ action: `tools/call:${toolName}`,
29
+ phase: "request"
30
+ })
31
+ }
32
+ const content = Array.isArray(result?.content) ? result.content : null
33
+ const contentText = content
34
+ ? content.map((item) => (typeof item?.text === "string" ? item.text : "")).join("\n").trim()
35
+ : ""
36
+ const output =
37
+ contentText ||
38
+ (typeof result?.output === "string" ? result.output : "") ||
39
+ (typeof result === "string" ? result : JSON.stringify(result))
40
+ return content ? { output, raw: result, content } : { output, raw: result }
41
+ }
42
+
43
+ async function requestJson({ serverName, method, url, body = null, timeoutMs = 10000, headers = {}, signal = null }) {
44
+ const action = method === "GET" ? url.split("/").pop() : body?.args ? "call_tool" : "request"
45
+ const startedAt = Date.now()
46
+ let status = null
47
+
48
+ try {
49
+ const res = await fetch(url, {
50
+ method,
51
+ headers: {
52
+ "content-type": "application/json",
53
+ ...headers
54
+ },
55
+ body: body ? JSON.stringify(body) : undefined,
56
+ signal: timeoutSignal(timeoutMs, signal)
57
+ })
58
+
59
+ status = res.status
60
+ const elapsed = Date.now() - startedAt
61
+
62
+ EventBus.emit({
63
+ type: EVENT_TYPES.MCP_REQUEST,
64
+ payload: { server: serverName, action, method, elapsed, status }
65
+ }).catch(() => {})
66
+
67
+ if (!res.ok) {
68
+ const text = await res.text().catch(() => "")
69
+ const reason = classifyHttpError(null, status)
70
+ throw new McpError(
71
+ `mcp server "${serverName}" HTTP ${status} on ${method} ${url}: ${text.slice(0, 500)}`,
72
+ { reason, server: serverName, action, phase: "request", statusCode: status }
73
+ )
74
+ }
75
+ return res.json().catch(() => ({}))
76
+ } catch (error) {
77
+ if (error instanceof McpError) throw error
78
+ const reason = classifyHttpError(error, status)
79
+ throw new McpError(
80
+ `mcp server "${serverName}" ${reason} on ${method} ${url}: ${error.message}`,
81
+ { reason, server: serverName, action, phase: "request", statusCode: status }
82
+ )
83
+ }
84
+ }
85
+
86
+ export function createHttpMcpClient(serverName, config) {
87
+ const baseUrl = String(config.url || "").replace(/\/$/, "")
88
+ const timeoutMs = Number(config.timeout_ms || 10000)
89
+ const headers = config.headers || {}
90
+
91
+ return {
92
+ serverName,
93
+ transport: "http",
94
+ async health() {
95
+ try {
96
+ await requestJson({ serverName, method: "GET", url: `${baseUrl}/health`, timeoutMs, headers })
97
+ return { ok: true }
98
+ } catch (error) {
99
+ return { ok: false, error: error.message, reason: error.reason || "unknown" }
100
+ }
101
+ },
102
+ async listTools() {
103
+ const out = await requestJson({ serverName, method: "GET", url: `${baseUrl}/tools`, timeoutMs, headers })
104
+ return Array.isArray(out?.tools) ? out.tools : []
105
+ },
106
+ async listPrompts() {
107
+ try {
108
+ const out = await requestJson({ serverName, method: "GET", url: `${baseUrl}/prompts`, timeoutMs, headers })
109
+ return Array.isArray(out?.prompts) ? out.prompts : []
110
+ } catch {
111
+ return []
112
+ }
113
+ },
114
+ async getPrompt(name, args = {}) {
115
+ return requestJson({
116
+ serverName,
117
+ method: "POST",
118
+ url: `${baseUrl}/prompts/${encodeURIComponent(name)}`,
119
+ body: { arguments: args },
120
+ timeoutMs,
121
+ headers
122
+ })
123
+ },
124
+ async listResources() {
125
+ try {
126
+ const out = await requestJson({ serverName, method: "GET", url: `${baseUrl}/resources`, timeoutMs, headers })
127
+ return Array.isArray(out?.resources) ? out.resources : []
128
+ } catch (error) {
129
+ if (error.reason === "server_crash" || error.reason === "timeout") throw error
130
+ return []
131
+ }
132
+ },
133
+ async listTemplates() {
134
+ try {
135
+ const out = await requestJson({ serverName, method: "GET", url: `${baseUrl}/templates`, timeoutMs, headers })
136
+ return Array.isArray(out?.templates) ? out.templates : []
137
+ } catch {
138
+ return []
139
+ }
140
+ },
141
+ async callTool(name, args = {}, signal = null) {
142
+ const result = await requestJson({
143
+ serverName,
144
+ method: "POST",
145
+ url: `${baseUrl}/tools/${encodeURIComponent(name)}`,
146
+ body: { args },
147
+ timeoutMs,
148
+ headers,
149
+ signal
150
+ })
151
+ return normalizeToolResult(result, serverName, name)
152
+ },
153
+ shutdown() {
154
+ // HTTP client is stateless — no persistent connections to clean up
155
+ }
156
+ }
157
+ }