agentikit 0.0.13 → 0.0.15

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 (156) hide show
  1. package/LICENSE +385 -0
  2. package/README.md +187 -110
  3. package/dist/{src/asset-spec.js → asset-spec.js} +11 -2
  4. package/dist/{src/asset-type-handler.js → asset-type-handler.js} +4 -3
  5. package/dist/cli.js +709 -0
  6. package/dist/common.js +192 -0
  7. package/dist/{src/config-cli.js → config-cli.js} +36 -30
  8. package/dist/{src/config.js → config.js} +95 -25
  9. package/dist/{src/db.js → db.js} +123 -51
  10. package/dist/{src/embedder.js → embedder.js} +57 -2
  11. package/dist/errors.js +28 -0
  12. package/dist/file-context.js +188 -0
  13. package/dist/{src/frontmatter.js → frontmatter.js} +1 -1
  14. package/dist/{src/github.js → github.js} +1 -3
  15. package/dist/handlers/agent-handler.js +19 -0
  16. package/dist/handlers/command-handler.js +20 -0
  17. package/dist/handlers/handler-bridge.js +51 -0
  18. package/dist/handlers/index.js +19 -0
  19. package/dist/handlers/knowledge-handler.js +32 -0
  20. package/dist/handlers/script-handler.js +42 -0
  21. package/dist/{src/handlers → handlers}/skill-handler.js +5 -6
  22. package/dist/{src/handlers → handlers}/tool-handler.js +8 -24
  23. package/dist/{src/indexer.js → indexer.js} +50 -26
  24. package/dist/init.js +43 -0
  25. package/dist/{src/llm.js → llm.js} +6 -11
  26. package/dist/lockfile.js +60 -0
  27. package/dist/matchers.js +163 -0
  28. package/dist/{src/metadata.js → metadata.js} +36 -16
  29. package/dist/{src/origin-resolve.js → origin-resolve.js} +10 -9
  30. package/dist/paths.js +83 -0
  31. package/dist/{src/registry-install.js → registry-install.js} +151 -19
  32. package/dist/{src/registry-resolve.js → registry-resolve.js} +190 -26
  33. package/dist/{src/registry-search.js → registry-search.js} +13 -21
  34. package/dist/renderers.js +286 -0
  35. package/dist/{src/ripgrep-install.js → ripgrep-install.js} +8 -27
  36. package/dist/{src/ripgrep-resolve.js → ripgrep-resolve.js} +21 -11
  37. package/dist/ripgrep.js +2 -0
  38. package/dist/self-update.js +226 -0
  39. package/dist/{src/stash-add.js → stash-add.js} +14 -4
  40. package/dist/stash-clone.js +115 -0
  41. package/dist/{src/stash-ref.js → stash-ref.js} +10 -9
  42. package/dist/{src/stash-registry.js → stash-registry.js} +21 -46
  43. package/dist/{src/stash-resolve.js → stash-resolve.js} +10 -9
  44. package/dist/{src/stash-search.js → stash-search.js} +89 -74
  45. package/dist/stash-show.js +74 -0
  46. package/dist/stash-source.js +127 -0
  47. package/dist/submit.js +557 -0
  48. package/dist/{src/tool-runner.js → tool-runner.js} +1 -5
  49. package/dist/{src/walker.js → walker.js} +38 -0
  50. package/dist/warn.js +20 -0
  51. package/package.json +13 -18
  52. package/dist/index.d.ts +0 -28
  53. package/dist/index.js +0 -15
  54. package/dist/src/asset-spec.d.ts +0 -16
  55. package/dist/src/asset-type-handler.d.ts +0 -27
  56. package/dist/src/cli.d.ts +0 -2
  57. package/dist/src/cli.js +0 -399
  58. package/dist/src/common.d.ts +0 -13
  59. package/dist/src/common.js +0 -60
  60. package/dist/src/config-cli.d.ts +0 -9
  61. package/dist/src/config.d.ts +0 -50
  62. package/dist/src/db.d.ts +0 -46
  63. package/dist/src/embedder.d.ts +0 -10
  64. package/dist/src/frontmatter.d.ts +0 -30
  65. package/dist/src/github.d.ts +0 -4
  66. package/dist/src/handlers/agent-handler.d.ts +0 -2
  67. package/dist/src/handlers/agent-handler.js +0 -26
  68. package/dist/src/handlers/command-handler.d.ts +0 -2
  69. package/dist/src/handlers/command-handler.js +0 -23
  70. package/dist/src/handlers/index.d.ts +0 -6
  71. package/dist/src/handlers/index.js +0 -23
  72. package/dist/src/handlers/knowledge-handler.d.ts +0 -2
  73. package/dist/src/handlers/knowledge-handler.js +0 -56
  74. package/dist/src/handlers/markdown-helpers.d.ts +0 -7
  75. package/dist/src/handlers/script-handler.d.ts +0 -2
  76. package/dist/src/handlers/script-handler.js +0 -78
  77. package/dist/src/handlers/skill-handler.d.ts +0 -2
  78. package/dist/src/handlers/tool-handler.d.ts +0 -2
  79. package/dist/src/indexer.d.ts +0 -22
  80. package/dist/src/init.d.ts +0 -19
  81. package/dist/src/init.js +0 -99
  82. package/dist/src/llm.d.ts +0 -15
  83. package/dist/src/markdown.d.ts +0 -18
  84. package/dist/src/metadata.d.ts +0 -41
  85. package/dist/src/origin-resolve.d.ts +0 -19
  86. package/dist/src/registry-install.d.ts +0 -11
  87. package/dist/src/registry-resolve.d.ts +0 -3
  88. package/dist/src/registry-search.d.ts +0 -27
  89. package/dist/src/registry-types.d.ts +0 -62
  90. package/dist/src/ripgrep-install.d.ts +0 -12
  91. package/dist/src/ripgrep-resolve.d.ts +0 -13
  92. package/dist/src/ripgrep.d.ts +0 -3
  93. package/dist/src/ripgrep.js +0 -2
  94. package/dist/src/stash-add.d.ts +0 -4
  95. package/dist/src/stash-clone.d.ts +0 -22
  96. package/dist/src/stash-clone.js +0 -83
  97. package/dist/src/stash-ref.d.ts +0 -31
  98. package/dist/src/stash-registry.d.ts +0 -18
  99. package/dist/src/stash-resolve.d.ts +0 -2
  100. package/dist/src/stash-search.d.ts +0 -8
  101. package/dist/src/stash-show.d.ts +0 -5
  102. package/dist/src/stash-show.js +0 -46
  103. package/dist/src/stash-source.d.ts +0 -24
  104. package/dist/src/stash-source.js +0 -81
  105. package/dist/src/stash-types.d.ts +0 -227
  106. package/dist/src/stash.d.ts +0 -16
  107. package/dist/src/stash.js +0 -9
  108. package/dist/src/tool-runner.d.ts +0 -35
  109. package/dist/src/walker.d.ts +0 -19
  110. package/src/asset-spec.ts +0 -85
  111. package/src/asset-type-handler.ts +0 -77
  112. package/src/cli.ts +0 -427
  113. package/src/common.ts +0 -76
  114. package/src/config-cli.ts +0 -499
  115. package/src/config.ts +0 -305
  116. package/src/db.ts +0 -411
  117. package/src/embedder.ts +0 -128
  118. package/src/frontmatter.ts +0 -95
  119. package/src/github.ts +0 -21
  120. package/src/handlers/agent-handler.ts +0 -32
  121. package/src/handlers/command-handler.ts +0 -29
  122. package/src/handlers/index.ts +0 -25
  123. package/src/handlers/knowledge-handler.ts +0 -62
  124. package/src/handlers/markdown-helpers.ts +0 -19
  125. package/src/handlers/script-handler.ts +0 -92
  126. package/src/handlers/skill-handler.ts +0 -37
  127. package/src/handlers/tool-handler.ts +0 -71
  128. package/src/indexer.ts +0 -392
  129. package/src/init.ts +0 -114
  130. package/src/llm.ts +0 -125
  131. package/src/markdown.ts +0 -106
  132. package/src/metadata.ts +0 -333
  133. package/src/origin-resolve.ts +0 -67
  134. package/src/registry-install.ts +0 -361
  135. package/src/registry-resolve.ts +0 -341
  136. package/src/registry-search.ts +0 -335
  137. package/src/registry-types.ts +0 -72
  138. package/src/ripgrep-install.ts +0 -200
  139. package/src/ripgrep-resolve.ts +0 -72
  140. package/src/ripgrep.ts +0 -3
  141. package/src/stash-add.ts +0 -63
  142. package/src/stash-clone.ts +0 -127
  143. package/src/stash-ref.ts +0 -99
  144. package/src/stash-registry.ts +0 -259
  145. package/src/stash-resolve.ts +0 -50
  146. package/src/stash-search.ts +0 -613
  147. package/src/stash-show.ts +0 -55
  148. package/src/stash-source.ts +0 -103
  149. package/src/stash-types.ts +0 -231
  150. package/src/stash.ts +0 -39
  151. package/src/tool-runner.ts +0 -142
  152. package/src/walker.ts +0 -53
  153. /package/dist/{src/handlers → handlers}/markdown-helpers.js +0 -0
  154. /package/dist/{src/markdown.js → markdown.js} +0 -0
  155. /package/dist/{src/registry-types.js → registry-types.js} +0 -0
  156. /package/dist/{src/stash-types.js → stash-types.js} +0 -0
package/src/stash-add.ts DELETED
@@ -1,63 +0,0 @@
1
- import { agentikitIndex } from "./indexer"
2
- import fs from "node:fs"
3
- import { resolveStashDir } from "./common"
4
- import { loadConfig } from "./config"
5
- import { upsertInstalledRegistryEntry, installRegistryRef } from "./registry-install"
6
- import type { AddResponse } from "./stash-types"
7
-
8
- export async function agentikitAdd(input: { ref: string }): Promise<AddResponse> {
9
- const ref = input.ref.trim()
10
- if (!ref) throw new Error("Install ref or local git directory is required.")
11
-
12
- const stashDir = resolveStashDir()
13
- const installed = await installRegistryRef(ref)
14
- const replaced = loadConfig().registry?.installed.find((entry) => entry.id === installed.id)
15
- const config = upsertInstalledRegistryEntry({
16
- id: installed.id,
17
- source: installed.source,
18
- ref: installed.ref,
19
- artifactUrl: installed.artifactUrl,
20
- resolvedVersion: installed.resolvedVersion,
21
- resolvedRevision: installed.resolvedRevision,
22
- stashRoot: installed.stashRoot,
23
- cacheDir: installed.cacheDir,
24
- installedAt: installed.installedAt,
25
- })
26
-
27
- if (replaced && replaced.cacheDir !== installed.cacheDir) {
28
- try {
29
- fs.rmSync(replaced.cacheDir, { recursive: true, force: true })
30
- } catch {
31
- // Best-effort cleanup only.
32
- }
33
- }
34
-
35
- const index = await agentikitIndex({ stashDir })
36
-
37
- return {
38
- stashDir,
39
- ref,
40
- installed: {
41
- id: installed.id,
42
- source: installed.source,
43
- ref: installed.ref,
44
- artifactUrl: installed.artifactUrl,
45
- resolvedVersion: installed.resolvedVersion,
46
- resolvedRevision: installed.resolvedRevision,
47
- stashRoot: installed.stashRoot,
48
- cacheDir: installed.cacheDir,
49
- extractedDir: installed.extractedDir,
50
- installedAt: installed.installedAt,
51
- },
52
- config: {
53
- mountedStashDirs: config.mountedStashDirs,
54
- installedRegistryCount: config.registry?.installed.length ?? 0,
55
- },
56
- index: {
57
- mode: index.mode,
58
- totalEntries: index.totalEntries,
59
- directoriesScanned: index.directoriesScanned,
60
- directoriesSkipped: index.directoriesSkipped,
61
- },
62
- }
63
- }
@@ -1,127 +0,0 @@
1
- import fs from "node:fs"
2
- import path from "node:path"
3
- import { TYPE_DIRS } from "./asset-spec"
4
- import { parseAssetRef, makeAssetRef } from "./stash-ref"
5
- import { resolveSourcesForOrigin } from "./origin-resolve"
6
- import { resolveAssetPath } from "./stash-resolve"
7
- import { resolveStashSources, findSourceForPath, type StashSource, type StashSourceKind } from "./stash-source"
8
-
9
- export interface CloneOptions {
10
- /** Source ref (e.g., npm:@scope/pkg//tool:deploy.sh) */
11
- sourceRef: string
12
- /** Optional new name for the cloned asset */
13
- newName?: string
14
- /** If true, overwrite existing asset in working stash */
15
- force?: boolean
16
- }
17
-
18
- export interface CloneResponse {
19
- source: {
20
- path: string
21
- sourceKind: StashSourceKind
22
- registryId?: string
23
- }
24
- destination: {
25
- path: string
26
- ref: string
27
- }
28
- overwritten: boolean
29
- }
30
-
31
- export async function agentikitClone(options: CloneOptions): Promise<CloneResponse> {
32
- const parsed = parseAssetRef(options.sourceRef)
33
- const allSources = resolveStashSources()
34
- const workingSource = allSources.find((s) => s.kind === "working")
35
- if (!workingSource) {
36
- throw new Error("No working stash configured. Run `akm init` first.")
37
- }
38
-
39
- const searchSources = resolveSourcesForOrigin(parsed.origin, allSources)
40
-
41
- let sourcePath: string | undefined
42
- let lastError: Error | undefined
43
- for (const source of searchSources) {
44
- try {
45
- sourcePath = resolveAssetPath(source.path, parsed.type, parsed.name)
46
- break
47
- } catch (err) {
48
- lastError = err instanceof Error ? err : new Error(String(err))
49
- }
50
- }
51
- if (!sourcePath) {
52
- throw lastError ?? new Error(`Source asset not found for ref: ${options.sourceRef}`)
53
- }
54
-
55
- const sourceSource = findSourceForPath(sourcePath, allSources)
56
- const sourceKind = sourceSource?.kind ?? "working"
57
-
58
- const destName = options.newName ?? parsed.name
59
- const typeDir = TYPE_DIRS[parsed.type]
60
- const workingDir = workingSource.path
61
-
62
- // Guard against self-clone
63
- if (parsed.type === "skill") {
64
- const sourceSkillDir = path.resolve(path.dirname(sourcePath))
65
- const destSkillDir = path.resolve(path.join(workingDir, typeDir, destName))
66
- if (sourceSkillDir === destSkillDir) {
67
- throw new Error(
68
- `Source and destination are the same path. Use --name to provide a new name for the clone.`,
69
- )
70
- }
71
- } else {
72
- const resolvedSource = path.resolve(sourcePath)
73
- const resolvedDest = path.resolve(path.join(workingDir, typeDir, destName))
74
- if (resolvedSource === resolvedDest) {
75
- throw new Error(
76
- `Source and destination are the same path. Use --name to provide a new name for the clone.`,
77
- )
78
- }
79
- }
80
-
81
- let destPath: string
82
- if (parsed.type === "skill") {
83
- const sourceSkillDir = path.dirname(sourcePath)
84
- const destSkillDir = path.join(workingDir, typeDir, destName)
85
- const overwritten = fs.existsSync(destSkillDir)
86
-
87
- if (overwritten && !options.force) {
88
- throw new Error(
89
- `Asset already exists in working stash: ${destSkillDir}. Use --force to overwrite.`,
90
- )
91
- }
92
-
93
- if (overwritten) {
94
- fs.rmSync(destSkillDir, { recursive: true, force: true })
95
- }
96
- fs.cpSync(sourceSkillDir, destSkillDir, { recursive: true })
97
-
98
- destPath = path.join(destSkillDir, "SKILL.md")
99
- const ref = makeAssetRef(parsed.type, destName, "local")
100
-
101
- return {
102
- source: { path: sourcePath, sourceKind, registryId: sourceSource?.registryId },
103
- destination: { path: destPath, ref },
104
- overwritten,
105
- }
106
- }
107
-
108
- destPath = path.join(workingDir, typeDir, destName)
109
- const overwritten = fs.existsSync(destPath)
110
-
111
- if (overwritten && !options.force) {
112
- throw new Error(
113
- `Asset already exists in working stash: ${destPath}. Use --force to overwrite.`,
114
- )
115
- }
116
-
117
- fs.mkdirSync(path.dirname(destPath), { recursive: true })
118
- fs.copyFileSync(sourcePath, destPath)
119
-
120
- const ref = makeAssetRef(parsed.type, destName, "local")
121
-
122
- return {
123
- source: { path: sourcePath, sourceKind, registryId: sourceSource?.registryId },
124
- destination: { path: destPath, ref },
125
- overwritten,
126
- }
127
- }
package/src/stash-ref.ts DELETED
@@ -1,99 +0,0 @@
1
- import path from "node:path"
2
- import { type AgentikitAssetType, isAssetType } from "./common"
3
-
4
- // ── Types ───────────────────────────────────────────────────────────────────
5
-
6
- export interface AssetRef {
7
- type: AgentikitAssetType
8
- name: string
9
- /**
10
- * Where to find this asset.
11
- * - undefined: search all sources (working → mounted → installed)
12
- * - "local": working stash only
13
- * - registry ref: e.g. "npm:@scope/pkg", "owner/repo", "github:owner/repo#v1"
14
- * - filesystem path: e.g. "/mnt/shared-stash"
15
- */
16
- origin?: string
17
- }
18
-
19
- // ── Construction ────────────────────────────────────────────────────────────
20
-
21
- /**
22
- * Build a ref string from components.
23
- *
24
- * Examples:
25
- * makeAssetRef("tool", "deploy.sh")
26
- * → "tool:deploy.sh"
27
- * makeAssetRef("tool", "deploy.sh", "npm:@scope/pkg")
28
- * → "npm:@scope/pkg//tool:deploy.sh"
29
- * makeAssetRef("skill", "code-review", "local")
30
- * → "local//skill:code-review"
31
- * makeAssetRef("tool", "db/migrate/run.sh", "owner/repo")
32
- * → "owner/repo//tool:db/migrate/run.sh"
33
- */
34
- export function makeAssetRef(
35
- type: AgentikitAssetType,
36
- name: string,
37
- origin?: string,
38
- ): string {
39
- validateName(name)
40
- const normalized = normalizeName(name)
41
- const asset = `${type}:${normalized}`
42
- if (!origin) return asset
43
- return `${origin}//${asset}`
44
- }
45
-
46
- // ── Parsing ─────────────────────────────────────────────────────────────────
47
-
48
- /**
49
- * Parse a ref string in the format `[origin//]type:name`.
50
- */
51
- export function parseAssetRef(ref: string): AssetRef {
52
- const trimmed = ref.trim()
53
- if (!trimmed) throw new Error("Empty ref.")
54
-
55
- let origin: string | undefined
56
- let body = trimmed
57
-
58
- const boundary = trimmed.indexOf("//")
59
- if (boundary >= 0) {
60
- origin = trimmed.slice(0, boundary)
61
- body = trimmed.slice(boundary + 2)
62
- if (!origin) throw new Error("Empty origin in ref.")
63
- }
64
-
65
- const colon = body.indexOf(":")
66
- if (colon <= 0) {
67
- throw new Error(`Invalid ref "${trimmed}". Expected [origin//]type:name`)
68
- }
69
-
70
- const rawType = body.slice(0, colon)
71
- const rawName = body.slice(colon + 1)
72
-
73
- if (!isAssetType(rawType)) {
74
- throw new Error(`Invalid asset type: "${rawType}".`)
75
- }
76
-
77
- validateName(rawName)
78
- const name = normalizeName(rawName)
79
-
80
- return { type: rawType, name, origin: origin || undefined }
81
- }
82
-
83
- // ── Validation ──────────────────────────────────────────────────────────────
84
-
85
- function validateName(name: string): void {
86
- if (!name) throw new Error("Empty asset name.")
87
- if (name.includes("\0")) throw new Error("Null byte in asset name.")
88
- if (/^[A-Za-z]:/.test(name)) throw new Error("Windows drive path in asset name.")
89
-
90
- const normalized = path.posix.normalize(name.replace(/\\/g, "/"))
91
- if (path.posix.isAbsolute(normalized)) throw new Error("Absolute path in asset name.")
92
- if (normalized === ".." || normalized.startsWith("../")) {
93
- throw new Error("Path traversal in asset name.")
94
- }
95
- }
96
-
97
- function normalizeName(name: string): string {
98
- return path.posix.normalize(name.replace(/\\/g, "/"))
99
- }
@@ -1,259 +0,0 @@
1
- import fs from "node:fs"
2
- import { resolveStashDir } from "./common"
3
- import { loadConfig } from "./config"
4
- import { agentikitIndex } from "./indexer"
5
- import {
6
- installRegistryRef,
7
- removeInstalledRegistryEntry,
8
- upsertInstalledRegistryEntry,
9
- } from "./registry-install"
10
- import { parseRegistryRef } from "./registry-resolve"
11
- import type { RegistryInstalledEntry } from "./registry-types"
12
- import type {
13
- ListResponse,
14
- RegistryInstallStatus,
15
- RemoveResponse,
16
- ReinstallResponse,
17
- UpdateResponse,
18
- } from "./stash-types"
19
-
20
- export async function agentikitList(input?: { stashDir?: string }): Promise<ListResponse> {
21
- const stashDir = input?.stashDir ?? resolveStashDir()
22
- const config = loadConfig()
23
- const installed = config.registry?.installed ?? []
24
-
25
- return {
26
- stashDir,
27
- installed: installed.map((entry) => ({
28
- ...entry,
29
- status: {
30
- cacheDirExists: directoryExists(entry.cacheDir),
31
- stashRootExists: directoryExists(entry.stashRoot),
32
- },
33
- })),
34
- totalInstalled: installed.length,
35
- }
36
- }
37
-
38
- export async function agentikitRemove(input: { target: string; stashDir?: string }): Promise<RemoveResponse> {
39
- const target = input.target.trim()
40
- if (!target) throw new Error("Target is required.")
41
-
42
- const stashDir = input.stashDir ?? resolveStashDir()
43
- const config = loadConfig()
44
- const installed = config.registry?.installed ?? []
45
- const entry = resolveInstalledTarget(installed, target)
46
-
47
- const updatedConfig = removeInstalledRegistryEntry(entry.id)
48
- cleanupDirectoryBestEffort(entry.cacheDir)
49
- const index = await agentikitIndex({ stashDir })
50
-
51
- return {
52
- stashDir,
53
- target,
54
- removed: {
55
- id: entry.id,
56
- source: entry.source,
57
- ref: entry.ref,
58
- cacheDir: entry.cacheDir,
59
- stashRoot: entry.stashRoot,
60
- },
61
- config: {
62
- mountedStashDirs: updatedConfig.mountedStashDirs,
63
- installedRegistryCount: updatedConfig.registry?.installed.length ?? 0,
64
- },
65
- index: {
66
- mode: index.mode,
67
- totalEntries: index.totalEntries,
68
- directoriesScanned: index.directoriesScanned,
69
- directoriesSkipped: index.directoriesSkipped,
70
- },
71
- }
72
- }
73
-
74
- export async function agentikitReinstall(input?: {
75
- target?: string
76
- all?: boolean
77
- stashDir?: string
78
- }): Promise<ReinstallResponse> {
79
- const stashDir = input?.stashDir ?? resolveStashDir()
80
- const target = input?.target?.trim()
81
- const all = input?.all === true
82
- const installedEntries = loadConfig().registry?.installed ?? []
83
- const selectedEntries = selectTargets(installedEntries, target, all)
84
-
85
- const processed: ReinstallResponse["processed"] = []
86
- for (const entry of selectedEntries) {
87
- const installed = await installRegistryRef(entry.ref)
88
- upsertInstalledRegistryEntry(toInstalledEntry(installed))
89
- if (entry.cacheDir !== installed.cacheDir) {
90
- cleanupDirectoryBestEffort(entry.cacheDir)
91
- }
92
-
93
- processed.push({
94
- id: entry.id,
95
- source: entry.source,
96
- ref: entry.ref,
97
- previousCacheDir: entry.cacheDir,
98
- installed: toInstallStatus(installed),
99
- })
100
- }
101
-
102
- const index = await agentikitIndex({ stashDir })
103
- const config = loadConfig()
104
-
105
- return {
106
- stashDir,
107
- target,
108
- all,
109
- processed,
110
- config: {
111
- mountedStashDirs: config.mountedStashDirs,
112
- installedRegistryCount: config.registry?.installed.length ?? 0,
113
- },
114
- index: {
115
- mode: index.mode,
116
- totalEntries: index.totalEntries,
117
- directoriesScanned: index.directoriesScanned,
118
- directoriesSkipped: index.directoriesSkipped,
119
- },
120
- }
121
- }
122
-
123
- export async function agentikitUpdate(input?: {
124
- target?: string
125
- all?: boolean
126
- stashDir?: string
127
- }): Promise<UpdateResponse> {
128
- const stashDir = input?.stashDir ?? resolveStashDir()
129
- const target = input?.target?.trim()
130
- const all = input?.all === true
131
- const installedEntries = loadConfig().registry?.installed ?? []
132
- const selectedEntries = selectTargets(installedEntries, target, all)
133
-
134
- const processed: UpdateResponse["processed"] = []
135
- for (const entry of selectedEntries) {
136
- const installed = await installRegistryRef(entry.ref)
137
- upsertInstalledRegistryEntry(toInstalledEntry(installed))
138
- if (entry.cacheDir !== installed.cacheDir) {
139
- cleanupDirectoryBestEffort(entry.cacheDir)
140
- }
141
-
142
- const versionChanged = (entry.resolvedVersion ?? "") !== (installed.resolvedVersion ?? "")
143
- const revisionChanged = (entry.resolvedRevision ?? "") !== (installed.resolvedRevision ?? "")
144
-
145
- processed.push({
146
- id: entry.id,
147
- source: entry.source,
148
- ref: entry.ref,
149
- previous: {
150
- resolvedVersion: entry.resolvedVersion,
151
- resolvedRevision: entry.resolvedRevision,
152
- cacheDir: entry.cacheDir,
153
- },
154
- installed: toInstallStatus(installed),
155
- changed: {
156
- version: versionChanged,
157
- revision: revisionChanged,
158
- any: versionChanged || revisionChanged,
159
- },
160
- })
161
- }
162
-
163
- const index = await agentikitIndex({ stashDir })
164
- const config = loadConfig()
165
-
166
- return {
167
- stashDir,
168
- target,
169
- all,
170
- processed,
171
- config: {
172
- mountedStashDirs: config.mountedStashDirs,
173
- installedRegistryCount: config.registry?.installed.length ?? 0,
174
- },
175
- index: {
176
- mode: index.mode,
177
- totalEntries: index.totalEntries,
178
- directoriesScanned: index.directoriesScanned,
179
- directoriesSkipped: index.directoriesSkipped,
180
- },
181
- }
182
- }
183
-
184
- function selectTargets(installed: RegistryInstalledEntry[], target: string | undefined, all: boolean): RegistryInstalledEntry[] {
185
- if (all && target) {
186
- throw new Error("Specify either <target> or --all, not both.")
187
- }
188
- if (all) return installed
189
- if (!target) {
190
- throw new Error("Either <target> or --all is required.")
191
- }
192
- return [resolveInstalledTarget(installed, target)]
193
- }
194
-
195
- function resolveInstalledTarget(installed: RegistryInstalledEntry[], target: string): RegistryInstalledEntry {
196
- const byId = installed.find((entry) => entry.id === target)
197
- if (byId) return byId
198
-
199
- const byRef = installed.find((entry) => entry.ref === target)
200
- if (byRef) return byRef
201
-
202
- let parsedId: string | undefined
203
- try {
204
- parsedId = parseRegistryRef(target).id
205
- } catch {
206
- parsedId = undefined
207
- }
208
- if (parsedId) {
209
- const byParsedId = installed.find((entry) => entry.id === parsedId)
210
- if (byParsedId) return byParsedId
211
- }
212
-
213
- throw new Error(`No installed registry entry matched target: ${target}`)
214
- }
215
-
216
- function toInstalledEntry(status: RegistryInstallStatus): RegistryInstalledEntry {
217
- return {
218
- id: status.id,
219
- source: status.source,
220
- ref: status.ref,
221
- artifactUrl: status.artifactUrl,
222
- resolvedVersion: status.resolvedVersion,
223
- resolvedRevision: status.resolvedRevision,
224
- stashRoot: status.stashRoot,
225
- cacheDir: status.cacheDir,
226
- installedAt: status.installedAt,
227
- }
228
- }
229
-
230
- function toInstallStatus(status: RegistryInstallStatus): RegistryInstallStatus {
231
- return {
232
- id: status.id,
233
- source: status.source,
234
- ref: status.ref,
235
- artifactUrl: status.artifactUrl,
236
- resolvedVersion: status.resolvedVersion,
237
- resolvedRevision: status.resolvedRevision,
238
- stashRoot: status.stashRoot,
239
- cacheDir: status.cacheDir,
240
- extractedDir: status.extractedDir,
241
- installedAt: status.installedAt,
242
- }
243
- }
244
-
245
- function cleanupDirectoryBestEffort(target: string): void {
246
- try {
247
- fs.rmSync(target, { recursive: true, force: true })
248
- } catch {
249
- // Best-effort cleanup only.
250
- }
251
- }
252
-
253
- function directoryExists(target: string): boolean {
254
- try {
255
- return fs.statSync(target).isDirectory()
256
- } catch {
257
- return false
258
- }
259
- }
@@ -1,50 +0,0 @@
1
- import fs from "node:fs"
2
- import path from "node:path"
3
- import { type AgentikitAssetType, hasErrnoCode, isWithin } from "./common"
4
- import { TYPE_DIRS, isRelevantAssetFile, resolveAssetPathFromName } from "./asset-spec"
5
-
6
- export function resolveAssetPath(stashDir: string, type: AgentikitAssetType, name: string): string {
7
- const root = path.join(stashDir, TYPE_DIRS[type])
8
- const target = resolveAssetPathFromName(type, root, name)
9
- const resolvedRoot = resolveAndValidateTypeRoot(root, type, name)
10
- const resolvedTarget = path.resolve(target)
11
- if (!isWithin(resolvedTarget, resolvedRoot)) {
12
- throw new Error("Ref resolves outside the stash root.")
13
- }
14
- if (!fs.existsSync(resolvedTarget) || !fs.statSync(resolvedTarget).isFile()) {
15
- throw new Error(`Stash asset not found for ref: ${type}:${name}`)
16
- }
17
- const realTarget = fs.realpathSync(resolvedTarget)
18
- if (!isWithin(realTarget, resolvedRoot)) {
19
- throw new Error("Ref resolves outside the stash root.")
20
- }
21
- if (!isRelevantAssetFile(type, path.basename(resolvedTarget))) {
22
- if (type === "tool") {
23
- throw new Error("Tool ref must resolve to a .sh, .ts, .js, .ps1, .cmd, or .bat file.")
24
- }
25
- if (type === "script") {
26
- throw new Error("Script ref must resolve to a file with a supported script extension. Refer to the Agentikit documentation for the complete list of supported script extensions.");
27
- }
28
- throw new Error(`Stash asset not found for ref: ${type}:${name}`)
29
- }
30
- return realTarget
31
- }
32
-
33
- function resolveAndValidateTypeRoot(root: string, type: AgentikitAssetType, name: string): string {
34
- const rootStat = readTypeRootStat(root, type, name)
35
- if (!rootStat.isDirectory()) {
36
- throw new Error(`Stash type root is not a directory for ref: ${type}:${name}`)
37
- }
38
- return fs.realpathSync(root)
39
- }
40
-
41
- function readTypeRootStat(root: string, type: AgentikitAssetType, name: string): fs.Stats {
42
- try {
43
- return fs.statSync(root)
44
- } catch (error: unknown) {
45
- if (hasErrnoCode(error, "ENOENT")) {
46
- throw new Error(`Stash type root not found for ref: ${type}:${name}`)
47
- }
48
- throw error
49
- }
50
- }