agentikit 0.0.8 → 0.0.12

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 (112) hide show
  1. package/README.md +135 -117
  2. package/dist/index.d.ts +13 -3
  3. package/dist/index.js +7 -1
  4. package/dist/src/asset-spec.d.ts +2 -0
  5. package/dist/src/asset-spec.js +22 -3
  6. package/dist/src/asset-type-handler.d.ts +27 -0
  7. package/dist/src/asset-type-handler.js +33 -0
  8. package/dist/src/cli.js +335 -100
  9. package/dist/src/common.d.ts +6 -1
  10. package/dist/src/common.js +18 -4
  11. package/dist/src/config-cli.d.ts +9 -0
  12. package/dist/src/config-cli.js +473 -0
  13. package/dist/src/config.d.ts +25 -6
  14. package/dist/src/config.js +188 -28
  15. package/dist/src/db.d.ts +46 -0
  16. package/dist/src/db.js +299 -0
  17. package/dist/src/embedder.js +12 -7
  18. package/dist/src/github.d.ts +4 -0
  19. package/dist/src/github.js +19 -0
  20. package/dist/src/handlers/agent-handler.d.ts +2 -0
  21. package/dist/src/handlers/agent-handler.js +26 -0
  22. package/dist/src/handlers/command-handler.d.ts +2 -0
  23. package/dist/src/handlers/command-handler.js +23 -0
  24. package/dist/src/handlers/index.d.ts +6 -0
  25. package/dist/src/handlers/index.js +23 -0
  26. package/dist/src/handlers/knowledge-handler.d.ts +2 -0
  27. package/dist/src/handlers/knowledge-handler.js +56 -0
  28. package/dist/src/handlers/markdown-helpers.d.ts +7 -0
  29. package/dist/src/handlers/markdown-helpers.js +15 -0
  30. package/dist/src/handlers/script-handler.d.ts +2 -0
  31. package/dist/src/handlers/script-handler.js +78 -0
  32. package/dist/src/handlers/skill-handler.d.ts +2 -0
  33. package/dist/src/handlers/skill-handler.js +30 -0
  34. package/dist/src/handlers/tool-handler.d.ts +2 -0
  35. package/dist/src/handlers/tool-handler.js +58 -0
  36. package/dist/src/indexer.d.ts +1 -23
  37. package/dist/src/indexer.js +162 -155
  38. package/dist/src/init.d.ts +2 -2
  39. package/dist/src/init.js +21 -9
  40. package/dist/src/llm.js +4 -3
  41. package/dist/src/metadata.d.ts +1 -1
  42. package/dist/src/metadata.js +22 -64
  43. package/dist/src/origin-resolve.d.ts +19 -0
  44. package/dist/src/origin-resolve.js +53 -0
  45. package/dist/src/registry-install.d.ts +11 -0
  46. package/dist/src/registry-install.js +315 -0
  47. package/dist/src/registry-resolve.d.ts +3 -0
  48. package/dist/src/registry-resolve.js +299 -0
  49. package/dist/src/registry-search.d.ts +27 -0
  50. package/dist/src/registry-search.js +263 -0
  51. package/dist/src/registry-types.d.ts +62 -0
  52. package/dist/src/registry-types.js +1 -0
  53. package/dist/src/stash-add.d.ts +4 -0
  54. package/dist/src/stash-add.js +59 -0
  55. package/dist/src/stash-clone.d.ts +22 -0
  56. package/dist/src/stash-clone.js +83 -0
  57. package/dist/src/stash-ref.d.ts +27 -3
  58. package/dist/src/stash-ref.js +63 -24
  59. package/dist/src/stash-registry.d.ts +18 -0
  60. package/dist/src/stash-registry.js +221 -0
  61. package/dist/src/stash-resolve.js +3 -0
  62. package/dist/src/stash-search.d.ts +3 -1
  63. package/dist/src/stash-search.js +357 -138
  64. package/dist/src/stash-show.d.ts +1 -1
  65. package/dist/src/stash-show.js +28 -89
  66. package/dist/src/stash-source.d.ts +24 -0
  67. package/dist/src/stash-source.js +81 -0
  68. package/dist/src/stash-types.d.ts +175 -1
  69. package/dist/src/stash.d.ts +9 -1
  70. package/dist/src/stash.js +5 -0
  71. package/dist/src/tool-runner.d.ts +1 -1
  72. package/dist/src/tool-runner.js +18 -5
  73. package/package.json +7 -2
  74. package/src/asset-spec.ts +20 -4
  75. package/src/asset-type-handler.ts +77 -0
  76. package/src/cli.ts +354 -103
  77. package/src/common.ts +23 -5
  78. package/src/config-cli.ts +499 -0
  79. package/src/config.ts +218 -37
  80. package/src/db.ts +411 -0
  81. package/src/embedder.ts +22 -11
  82. package/src/github.ts +21 -0
  83. package/src/handlers/agent-handler.ts +32 -0
  84. package/src/handlers/command-handler.ts +29 -0
  85. package/src/handlers/index.ts +25 -0
  86. package/src/handlers/knowledge-handler.ts +62 -0
  87. package/src/handlers/markdown-helpers.ts +19 -0
  88. package/src/handlers/script-handler.ts +92 -0
  89. package/src/handlers/skill-handler.ts +37 -0
  90. package/src/handlers/tool-handler.ts +71 -0
  91. package/src/indexer.ts +208 -187
  92. package/src/init.ts +17 -9
  93. package/src/llm.ts +4 -3
  94. package/src/metadata.ts +21 -65
  95. package/src/origin-resolve.ts +67 -0
  96. package/src/registry-install.ts +361 -0
  97. package/src/registry-resolve.ts +341 -0
  98. package/src/registry-search.ts +335 -0
  99. package/src/registry-types.ts +72 -0
  100. package/src/stash-add.ts +63 -0
  101. package/src/stash-clone.ts +127 -0
  102. package/src/stash-ref.ts +84 -26
  103. package/src/stash-registry.ts +259 -0
  104. package/src/stash-resolve.ts +3 -0
  105. package/src/stash-search.ts +425 -155
  106. package/src/stash-show.ts +33 -82
  107. package/src/stash-source.ts +103 -0
  108. package/src/stash-types.ts +186 -1
  109. package/src/stash.ts +23 -0
  110. package/src/tool-runner.ts +18 -5
  111. package/dist/src/similarity.d.ts +0 -34
  112. package/src/similarity.ts +0 -271
package/src/config.ts CHANGED
@@ -1,23 +1,33 @@
1
1
  import fs from "node:fs"
2
2
  import path from "node:path"
3
- import { resolveStashDir } from "./common"
3
+ import type { RegistryInstalledEntry, RegistrySource } from "./registry-types"
4
4
 
5
5
  // ── Types ───────────────────────────────────────────────────────────────────
6
6
 
7
7
  export interface EmbeddingConnectionConfig {
8
+ /** Provider name for display/CLI switching (e.g. "openai", "ollama") */
9
+ provider?: string
8
10
  /** OpenAI-compatible embeddings endpoint (e.g. "http://localhost:11434/v1/embeddings") */
9
11
  endpoint: string
10
12
  /** Model name to use for embeddings (e.g. "nomic-embed-text") */
11
13
  model: string
14
+ /** Optional output dimension for providers that support it */
15
+ dimension?: number
12
16
  /** Optional API key for authenticated endpoints */
13
17
  apiKey?: string
14
18
  }
15
19
 
16
20
  export interface LlmConnectionConfig {
21
+ /** Provider name for display/CLI switching (e.g. "openai", "ollama") */
22
+ provider?: string
17
23
  /** OpenAI-compatible chat completions endpoint (e.g. "http://localhost:11434/v1/chat/completions") */
18
24
  endpoint: string
19
25
  /** Model name to use (e.g. "llama3.2") */
20
26
  model: string
27
+ /** Optional sampling temperature */
28
+ temperature?: number
29
+ /** Optional response token limit */
30
+ maxTokens?: number
21
31
  /** Optional API key for authenticated endpoints */
22
32
  apiKey?: string
23
33
  }
@@ -25,60 +35,119 @@ export interface LlmConnectionConfig {
25
35
  export interface AgentikitConfig {
26
36
  /** Whether semantic search is enabled. Default: true */
27
37
  semanticSearch: boolean
28
- /** Additional stash directories to search alongside the primary one */
29
- additionalStashDirs: string[]
38
+ /** User-mounted read-only stash directories */
39
+ mountedStashDirs: string[]
30
40
  /** OpenAI-compatible embedding endpoint config. If not set, uses local @xenova/transformers */
31
41
  embedding?: EmbeddingConnectionConfig
32
42
  /** OpenAI-compatible LLM endpoint config for metadata generation. If not set, uses heuristic generation */
33
43
  llm?: LlmConnectionConfig
44
+ /** Installed registry sources and local cache metadata */
45
+ registry?: RegistryConfig
46
+ /** Registry index URLs for kit discovery. Default: official agentikit-registry on GitHub */
47
+ registryUrls?: string[]
48
+ }
49
+
50
+ export interface RegistryConfig {
51
+ installed: RegistryInstalledEntry[]
34
52
  }
35
53
 
36
54
  // ── Defaults ────────────────────────────────────────────────────────────────
37
55
 
38
56
  export const DEFAULT_CONFIG: AgentikitConfig = {
39
57
  semanticSearch: true,
40
- additionalStashDirs: [],
58
+ mountedStashDirs: [],
41
59
  }
42
60
 
43
61
  // ── Paths ───────────────────────────────────────────────────────────────────
44
62
 
45
- export function getConfigPath(stashDir: string): string {
46
- return path.join(stashDir, "config.json")
63
+ export function getConfigDir(
64
+ env: NodeJS.ProcessEnv = process.env,
65
+ platform = process.platform,
66
+ ): string {
67
+ if (platform === "win32") {
68
+ const appData = env.APPDATA?.trim()
69
+ if (appData) return path.join(appData, "agentikit")
70
+
71
+ const userProfile = env.USERPROFILE?.trim()
72
+ if (!userProfile) {
73
+ throw new Error("Unable to determine config directory. Set APPDATA or USERPROFILE.")
74
+ }
75
+ return path.join(userProfile, "AppData", "Roaming", "agentikit")
76
+ }
77
+
78
+ const xdgConfigHome = env.XDG_CONFIG_HOME?.trim()
79
+ if (xdgConfigHome) return path.join(xdgConfigHome, "agentikit")
80
+
81
+ const home = env.HOME?.trim()
82
+ if (!home) {
83
+ throw new Error("Unable to determine config directory. Set XDG_CONFIG_HOME or HOME.")
84
+ }
85
+ return path.join(home, ".config", "agentikit")
86
+ }
87
+
88
+ export function getConfigPath(): string {
89
+ return path.join(getConfigDir(), "config.json")
47
90
  }
48
91
 
49
92
  // ── Load / Save / Update ────────────────────────────────────────────────────
50
93
 
51
- export function loadConfig(stashDir?: string): AgentikitConfig {
52
- const dir = stashDir ?? resolveStashDir()
53
- const configPath = getConfigPath(dir)
94
+ export function loadConfig(): AgentikitConfig {
95
+ const configPath = getConfigPath()
96
+ const raw = readConfigObject(configPath)
97
+ const config = raw ? pickKnownKeys(raw) : { ...DEFAULT_CONFIG }
54
98
 
55
- let raw: Record<string, unknown>
56
- try {
57
- raw = JSON.parse(fs.readFileSync(configPath, "utf8"))
58
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
59
- return { ...DEFAULT_CONFIG }
60
- }
61
- } catch {
62
- return { ...DEFAULT_CONFIG }
99
+ // Inject API keys from environment variables.
100
+ // API keys should be provided via AKM_EMBED_API_KEY and AKM_LLM_API_KEY
101
+ // rather than stored in the config file.
102
+ if (config.embedding && !config.embedding.apiKey) {
103
+ const envKey = process.env.AKM_EMBED_API_KEY?.trim()
104
+ if (envKey) config.embedding.apiKey = envKey
63
105
  }
106
+ if (config.llm && !config.llm.apiKey) {
107
+ const envKey = process.env.AKM_LLM_API_KEY?.trim()
108
+ if (envKey) config.llm.apiKey = envKey
109
+ }
110
+
111
+ return config
112
+ }
64
113
 
65
- return pickKnownKeys(raw)
114
+ export function saveConfig(config: AgentikitConfig): void {
115
+ const configPath = getConfigPath()
116
+ const dir = path.dirname(configPath)
117
+ fs.mkdirSync(dir, { recursive: true })
118
+ const sanitized = sanitizeConfigForWrite(config)
119
+ const tmpPath = configPath + `.tmp.${process.pid}`
120
+ try {
121
+ fs.writeFileSync(tmpPath, JSON.stringify(sanitized, null, 2) + "\n", "utf8")
122
+ fs.renameSync(tmpPath, configPath)
123
+ } catch (err) {
124
+ try { fs.unlinkSync(tmpPath) } catch { /* ignore cleanup failure */ }
125
+ throw err
126
+ }
66
127
  }
67
128
 
68
- export function saveConfig(config: AgentikitConfig, stashDir?: string): void {
69
- const dir = stashDir ?? resolveStashDir()
70
- const configPath = getConfigPath(dir)
71
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8")
129
+ /**
130
+ * Strip apiKey fields before writing config to disk.
131
+ * API keys should be provided via environment variables
132
+ * AKM_EMBED_API_KEY and AKM_LLM_API_KEY.
133
+ */
134
+ function sanitizeConfigForWrite(config: AgentikitConfig): AgentikitConfig {
135
+ const sanitized = { ...config }
136
+ if (sanitized.embedding) {
137
+ const { apiKey, ...rest } = sanitized.embedding
138
+ sanitized.embedding = rest as EmbeddingConnectionConfig
139
+ }
140
+ if (sanitized.llm) {
141
+ const { apiKey, ...rest } = sanitized.llm
142
+ sanitized.llm = rest as LlmConnectionConfig
143
+ }
144
+ return sanitized
72
145
  }
73
146
 
74
- export function updateConfig(
75
- partial: Partial<AgentikitConfig>,
76
- stashDir?: string,
77
- ): AgentikitConfig {
78
- const dir = stashDir ?? resolveStashDir()
79
- const current = loadConfig(dir)
147
+ export function updateConfig(partial: Partial<AgentikitConfig>): AgentikitConfig {
148
+ const current = loadConfig()
80
149
  const merged: AgentikitConfig = { ...current, ...partial }
81
- saveConfig(merged, dir)
150
+ saveConfig(merged)
82
151
  return merged
83
152
  }
84
153
 
@@ -91,34 +160,146 @@ function pickKnownKeys(raw: Record<string, unknown>): AgentikitConfig {
91
160
  config.semanticSearch = raw.semanticSearch
92
161
  }
93
162
 
94
- if (Array.isArray(raw.additionalStashDirs)) {
95
- config.additionalStashDirs = raw.additionalStashDirs.filter(
163
+ if (Array.isArray(raw.mountedStashDirs)) {
164
+ config.mountedStashDirs = raw.mountedStashDirs.filter(
96
165
  (d): d is string => typeof d === "string",
97
166
  )
98
167
  }
99
168
 
100
- const embedding = parseConnectionConfig(raw.embedding)
169
+ const embedding = parseEmbeddingConfig(raw.embedding)
101
170
  if (embedding) config.embedding = embedding
102
171
 
103
- const llm = parseConnectionConfig(raw.llm)
172
+ const llm = parseLlmConfig(raw.llm)
104
173
  if (llm) config.llm = llm
105
174
 
175
+ const registry = parseRegistryConfig(raw.registry)
176
+ if (registry) config.registry = registry
177
+
178
+ if (Array.isArray(raw.registryUrls)) {
179
+ config.registryUrls = raw.registryUrls.filter(
180
+ (u): u is string => typeof u === "string" && u.startsWith("http"),
181
+ )
182
+ }
183
+
106
184
  return config
107
185
  }
108
186
 
109
- function parseConnectionConfig(
110
- value: unknown,
111
- ): EmbeddingConnectionConfig | LlmConnectionConfig | undefined {
187
+ function readConfigObject(configPath: string): Record<string, unknown> | undefined {
188
+ try {
189
+ const raw = JSON.parse(fs.readFileSync(configPath, "utf8"))
190
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return undefined
191
+ return raw
192
+ } catch {
193
+ return undefined
194
+ }
195
+ }
196
+
197
+ function parseEmbeddingConfig(value: unknown): EmbeddingConnectionConfig | undefined {
112
198
  if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined
113
199
  const obj = value as Record<string, unknown>
114
200
  if (typeof obj.endpoint !== "string" || !obj.endpoint) return undefined
115
201
  if (typeof obj.model !== "string" || !obj.model) return undefined
116
- const result: { endpoint: string; model: string; apiKey?: string } = {
202
+ const result: EmbeddingConnectionConfig = {
117
203
  endpoint: obj.endpoint,
118
204
  model: obj.model,
119
205
  }
206
+ if (typeof obj.provider === "string" && obj.provider) {
207
+ result.provider = obj.provider
208
+ }
209
+ if ("dimension" in obj) {
210
+ if (
211
+ typeof obj.dimension !== "number" ||
212
+ !Number.isFinite(obj.dimension) ||
213
+ !Number.isInteger(obj.dimension) ||
214
+ obj.dimension <= 0
215
+ ) {
216
+ return undefined
217
+ }
218
+ result.dimension = obj.dimension
219
+ }
120
220
  if (typeof obj.apiKey === "string" && obj.apiKey) {
121
221
  result.apiKey = obj.apiKey
122
222
  }
123
223
  return result
124
224
  }
225
+
226
+ function parseLlmConfig(value: unknown): LlmConnectionConfig | undefined {
227
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined
228
+ const obj = value as Record<string, unknown>
229
+ if (typeof obj.endpoint !== "string" || !obj.endpoint) return undefined
230
+ if (typeof obj.model !== "string" || !obj.model) return undefined
231
+ const result: LlmConnectionConfig = {
232
+ endpoint: obj.endpoint,
233
+ model: obj.model,
234
+ }
235
+ if (typeof obj.provider === "string" && obj.provider) {
236
+ result.provider = obj.provider
237
+ }
238
+ if (typeof obj.temperature === "number" && Number.isFinite(obj.temperature)) {
239
+ result.temperature = obj.temperature
240
+ }
241
+ if ("maxTokens" in obj) {
242
+ if (
243
+ typeof obj.maxTokens !== "number" ||
244
+ !Number.isFinite(obj.maxTokens) ||
245
+ !Number.isInteger(obj.maxTokens) ||
246
+ obj.maxTokens <= 0
247
+ ) {
248
+ return undefined
249
+ }
250
+ result.maxTokens = obj.maxTokens
251
+ }
252
+ if (typeof obj.apiKey === "string" && obj.apiKey) {
253
+ result.apiKey = obj.apiKey
254
+ }
255
+ return result
256
+ }
257
+
258
+ function parseRegistryConfig(value: unknown): RegistryConfig | undefined {
259
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined
260
+ const obj = value as Record<string, unknown>
261
+ if (!Array.isArray(obj.installed)) return undefined
262
+
263
+ const installed = obj.installed
264
+ .map((entry) => parseRegistryInstalledEntry(entry))
265
+ .filter((entry): entry is RegistryInstalledEntry => entry !== undefined)
266
+
267
+ return { installed }
268
+ }
269
+
270
+ function parseRegistryInstalledEntry(value: unknown): RegistryInstalledEntry | undefined {
271
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined
272
+ const obj = value as Record<string, unknown>
273
+
274
+ const id = asNonEmptyString(obj.id)
275
+ const source = asRegistrySource(obj.source)
276
+ const ref = asNonEmptyString(obj.ref)
277
+ const artifactUrl = asNonEmptyString(obj.artifactUrl)
278
+ const stashRoot = asNonEmptyString(obj.stashRoot)
279
+ const cacheDir = asNonEmptyString(obj.cacheDir)
280
+ const installedAt = asNonEmptyString(obj.installedAt)
281
+ if (!id || !source || !ref || !artifactUrl || !stashRoot || !cacheDir || !installedAt) return undefined
282
+
283
+ const entry: RegistryInstalledEntry = {
284
+ id,
285
+ source,
286
+ ref,
287
+ artifactUrl,
288
+ stashRoot,
289
+ cacheDir,
290
+ installedAt,
291
+ }
292
+ const resolvedVersion = asNonEmptyString(obj.resolvedVersion)
293
+ if (resolvedVersion) entry.resolvedVersion = resolvedVersion
294
+ const resolvedRevision = asNonEmptyString(obj.resolvedRevision)
295
+ if (resolvedRevision) entry.resolvedRevision = resolvedRevision
296
+ return entry
297
+ }
298
+
299
+ function asNonEmptyString(value: unknown): string | undefined {
300
+ return typeof value === "string" && value ? value : undefined
301
+ }
302
+
303
+ function asRegistrySource(value: unknown): RegistrySource | undefined {
304
+ return value === "npm" || value === "github" || value === "git" ? value : undefined
305
+ }