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.
- package/LICENSE +385 -0
- package/README.md +187 -110
- package/dist/{src/asset-spec.js → asset-spec.js} +11 -2
- package/dist/{src/asset-type-handler.js → asset-type-handler.js} +4 -3
- package/dist/cli.js +709 -0
- package/dist/common.js +192 -0
- package/dist/{src/config-cli.js → config-cli.js} +36 -30
- package/dist/{src/config.js → config.js} +95 -25
- package/dist/{src/db.js → db.js} +123 -51
- package/dist/{src/embedder.js → embedder.js} +57 -2
- package/dist/errors.js +28 -0
- package/dist/file-context.js +188 -0
- package/dist/{src/frontmatter.js → frontmatter.js} +1 -1
- package/dist/{src/github.js → github.js} +1 -3
- package/dist/handlers/agent-handler.js +19 -0
- package/dist/handlers/command-handler.js +20 -0
- package/dist/handlers/handler-bridge.js +51 -0
- package/dist/handlers/index.js +19 -0
- package/dist/handlers/knowledge-handler.js +32 -0
- package/dist/handlers/script-handler.js +42 -0
- package/dist/{src/handlers → handlers}/skill-handler.js +5 -6
- package/dist/{src/handlers → handlers}/tool-handler.js +8 -24
- package/dist/{src/indexer.js → indexer.js} +50 -26
- package/dist/init.js +43 -0
- package/dist/{src/llm.js → llm.js} +6 -11
- package/dist/lockfile.js +60 -0
- package/dist/matchers.js +163 -0
- package/dist/{src/metadata.js → metadata.js} +36 -16
- package/dist/{src/origin-resolve.js → origin-resolve.js} +10 -9
- package/dist/paths.js +83 -0
- package/dist/{src/registry-install.js → registry-install.js} +151 -19
- package/dist/{src/registry-resolve.js → registry-resolve.js} +190 -26
- package/dist/{src/registry-search.js → registry-search.js} +13 -21
- package/dist/renderers.js +286 -0
- package/dist/{src/ripgrep-install.js → ripgrep-install.js} +8 -27
- package/dist/{src/ripgrep-resolve.js → ripgrep-resolve.js} +21 -11
- package/dist/ripgrep.js +2 -0
- package/dist/self-update.js +226 -0
- package/dist/{src/stash-add.js → stash-add.js} +14 -4
- package/dist/stash-clone.js +115 -0
- package/dist/{src/stash-ref.js → stash-ref.js} +10 -9
- package/dist/{src/stash-registry.js → stash-registry.js} +21 -46
- package/dist/{src/stash-resolve.js → stash-resolve.js} +10 -9
- package/dist/{src/stash-search.js → stash-search.js} +89 -74
- package/dist/stash-show.js +74 -0
- package/dist/stash-source.js +127 -0
- package/dist/submit.js +557 -0
- package/dist/{src/tool-runner.js → tool-runner.js} +1 -5
- package/dist/{src/walker.js → walker.js} +38 -0
- package/dist/warn.js +20 -0
- package/package.json +13 -18
- package/dist/index.d.ts +0 -28
- package/dist/index.js +0 -15
- package/dist/src/asset-spec.d.ts +0 -16
- package/dist/src/asset-type-handler.d.ts +0 -27
- package/dist/src/cli.d.ts +0 -2
- package/dist/src/cli.js +0 -399
- package/dist/src/common.d.ts +0 -13
- package/dist/src/common.js +0 -60
- package/dist/src/config-cli.d.ts +0 -9
- package/dist/src/config.d.ts +0 -50
- package/dist/src/db.d.ts +0 -46
- package/dist/src/embedder.d.ts +0 -10
- package/dist/src/frontmatter.d.ts +0 -30
- package/dist/src/github.d.ts +0 -4
- package/dist/src/handlers/agent-handler.d.ts +0 -2
- package/dist/src/handlers/agent-handler.js +0 -26
- package/dist/src/handlers/command-handler.d.ts +0 -2
- package/dist/src/handlers/command-handler.js +0 -23
- package/dist/src/handlers/index.d.ts +0 -6
- package/dist/src/handlers/index.js +0 -23
- package/dist/src/handlers/knowledge-handler.d.ts +0 -2
- package/dist/src/handlers/knowledge-handler.js +0 -56
- package/dist/src/handlers/markdown-helpers.d.ts +0 -7
- package/dist/src/handlers/script-handler.d.ts +0 -2
- package/dist/src/handlers/script-handler.js +0 -78
- package/dist/src/handlers/skill-handler.d.ts +0 -2
- package/dist/src/handlers/tool-handler.d.ts +0 -2
- package/dist/src/indexer.d.ts +0 -22
- package/dist/src/init.d.ts +0 -19
- package/dist/src/init.js +0 -99
- package/dist/src/llm.d.ts +0 -15
- package/dist/src/markdown.d.ts +0 -18
- package/dist/src/metadata.d.ts +0 -41
- package/dist/src/origin-resolve.d.ts +0 -19
- package/dist/src/registry-install.d.ts +0 -11
- package/dist/src/registry-resolve.d.ts +0 -3
- package/dist/src/registry-search.d.ts +0 -27
- package/dist/src/registry-types.d.ts +0 -62
- package/dist/src/ripgrep-install.d.ts +0 -12
- package/dist/src/ripgrep-resolve.d.ts +0 -13
- package/dist/src/ripgrep.d.ts +0 -3
- package/dist/src/ripgrep.js +0 -2
- package/dist/src/stash-add.d.ts +0 -4
- package/dist/src/stash-clone.d.ts +0 -22
- package/dist/src/stash-clone.js +0 -83
- package/dist/src/stash-ref.d.ts +0 -31
- package/dist/src/stash-registry.d.ts +0 -18
- package/dist/src/stash-resolve.d.ts +0 -2
- package/dist/src/stash-search.d.ts +0 -8
- package/dist/src/stash-show.d.ts +0 -5
- package/dist/src/stash-show.js +0 -46
- package/dist/src/stash-source.d.ts +0 -24
- package/dist/src/stash-source.js +0 -81
- package/dist/src/stash-types.d.ts +0 -227
- package/dist/src/stash.d.ts +0 -16
- package/dist/src/stash.js +0 -9
- package/dist/src/tool-runner.d.ts +0 -35
- package/dist/src/walker.d.ts +0 -19
- package/src/asset-spec.ts +0 -85
- package/src/asset-type-handler.ts +0 -77
- package/src/cli.ts +0 -427
- package/src/common.ts +0 -76
- package/src/config-cli.ts +0 -499
- package/src/config.ts +0 -305
- package/src/db.ts +0 -411
- package/src/embedder.ts +0 -128
- package/src/frontmatter.ts +0 -95
- package/src/github.ts +0 -21
- package/src/handlers/agent-handler.ts +0 -32
- package/src/handlers/command-handler.ts +0 -29
- package/src/handlers/index.ts +0 -25
- package/src/handlers/knowledge-handler.ts +0 -62
- package/src/handlers/markdown-helpers.ts +0 -19
- package/src/handlers/script-handler.ts +0 -92
- package/src/handlers/skill-handler.ts +0 -37
- package/src/handlers/tool-handler.ts +0 -71
- package/src/indexer.ts +0 -392
- package/src/init.ts +0 -114
- package/src/llm.ts +0 -125
- package/src/markdown.ts +0 -106
- package/src/metadata.ts +0 -333
- package/src/origin-resolve.ts +0 -67
- package/src/registry-install.ts +0 -361
- package/src/registry-resolve.ts +0 -341
- package/src/registry-search.ts +0 -335
- package/src/registry-types.ts +0 -72
- package/src/ripgrep-install.ts +0 -200
- package/src/ripgrep-resolve.ts +0 -72
- package/src/ripgrep.ts +0 -3
- package/src/stash-add.ts +0 -63
- package/src/stash-clone.ts +0 -127
- package/src/stash-ref.ts +0 -99
- package/src/stash-registry.ts +0 -259
- package/src/stash-resolve.ts +0 -50
- package/src/stash-search.ts +0 -613
- package/src/stash-show.ts +0 -55
- package/src/stash-source.ts +0 -103
- package/src/stash-types.ts +0 -231
- package/src/stash.ts +0 -39
- package/src/tool-runner.ts +0 -142
- package/src/walker.ts +0 -53
- /package/dist/{src/handlers → handlers}/markdown-helpers.js +0 -0
- /package/dist/{src/markdown.js → markdown.js} +0 -0
- /package/dist/{src/registry-types.js → registry-types.js} +0 -0
- /package/dist/{src/stash-types.js → stash-types.js} +0 -0
package/src/markdown.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { parseFrontmatter } from "./frontmatter"
|
|
2
|
-
|
|
3
|
-
// ── Types ───────────────────────────────────────────────────────────────────
|
|
4
|
-
|
|
5
|
-
export interface TocHeading {
|
|
6
|
-
level: number
|
|
7
|
-
text: string
|
|
8
|
-
line: number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface KnowledgeToc {
|
|
12
|
-
headings: TocHeading[]
|
|
13
|
-
totalLines: number
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// ── Parsing ─────────────────────────────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
export function parseMarkdownToc(content: string): KnowledgeToc {
|
|
19
|
-
const lines = content.split(/\r?\n/)
|
|
20
|
-
const headings: TocHeading[] = []
|
|
21
|
-
|
|
22
|
-
const parsed = parseFrontmatter(content)
|
|
23
|
-
const start = parsed.frontmatter ? parsed.bodyStartLine - 1 : 0
|
|
24
|
-
|
|
25
|
-
for (let i = start; i < lines.length; i++) {
|
|
26
|
-
const match = lines[i].match(/^(#{1,6})\s+(.+)$/)
|
|
27
|
-
if (match) {
|
|
28
|
-
headings.push({
|
|
29
|
-
level: match[1].length,
|
|
30
|
-
text: match[2].replace(/\s+#+\s*$/, "").trim(),
|
|
31
|
-
line: i + 1,
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return { headings, totalLines: lines.length }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ── Extraction ──────────────────────────────────────────────────────────────
|
|
40
|
-
|
|
41
|
-
export function extractSection(
|
|
42
|
-
content: string,
|
|
43
|
-
heading: string,
|
|
44
|
-
): { content: string; startLine: number; endLine: number } | null {
|
|
45
|
-
const lines = content.split(/\r?\n/)
|
|
46
|
-
const target = heading.toLowerCase()
|
|
47
|
-
|
|
48
|
-
let startIdx = -1
|
|
49
|
-
let startLevel = 0
|
|
50
|
-
|
|
51
|
-
for (let i = 0; i < lines.length; i++) {
|
|
52
|
-
const match = lines[i].match(/^(#{1,6})\s+(.+)$/)
|
|
53
|
-
if (!match) continue
|
|
54
|
-
const text = match[2].replace(/\s+#+\s*$/, "").trim()
|
|
55
|
-
if (text.toLowerCase() === target && startIdx === -1) {
|
|
56
|
-
startIdx = i
|
|
57
|
-
startLevel = match[1].length
|
|
58
|
-
} else if (startIdx !== -1 && match[1].length <= startLevel) {
|
|
59
|
-
return {
|
|
60
|
-
content: lines.slice(startIdx, i).join("\n"),
|
|
61
|
-
startLine: startIdx + 1,
|
|
62
|
-
endLine: i,
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (startIdx === -1) return null
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
content: lines.slice(startIdx).join("\n"),
|
|
71
|
-
startLine: startIdx + 1,
|
|
72
|
-
endLine: lines.length,
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function extractLineRange(content: string, start: number, end: number): string {
|
|
77
|
-
const lines = content.split(/\r?\n/)
|
|
78
|
-
if (end < start) return ""
|
|
79
|
-
const s = Math.max(1, Math.min(start, lines.length))
|
|
80
|
-
const e = Math.min(end, lines.length)
|
|
81
|
-
return lines.slice(s - 1, e).join("\n")
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function extractFrontmatterOnly(content: string): string | null {
|
|
85
|
-
const parsed = parseFrontmatter(content)
|
|
86
|
-
return parsed.frontmatter
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// ── Formatting ──────────────────────────────────────────────────────────────
|
|
90
|
-
|
|
91
|
-
export function formatToc(toc: KnowledgeToc): string {
|
|
92
|
-
if (toc.headings.length === 0) {
|
|
93
|
-
return `(no headings found — ${toc.totalLines} lines total)`
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const lineWidth = String(toc.totalLines).length
|
|
97
|
-
const parts = toc.headings.map((h) => {
|
|
98
|
-
const lineNum = `L${String(h.line).padStart(lineWidth)}`
|
|
99
|
-
const indent = " ".repeat(h.level - 1)
|
|
100
|
-
const prefix = "#".repeat(h.level)
|
|
101
|
-
return `${lineNum} ${indent}${prefix} ${h.text}`
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
parts.push(`\n${toc.totalLines} lines total`)
|
|
105
|
-
return parts.join("\n")
|
|
106
|
-
}
|
package/src/metadata.ts
DELETED
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs"
|
|
2
|
-
import path from "node:path"
|
|
3
|
-
import { type AgentikitAssetType, isAssetType } from "./common"
|
|
4
|
-
import { SCRIPT_EXTENSIONS, isRelevantAssetFile, deriveCanonicalAssetName } from "./asset-spec"
|
|
5
|
-
import { parseFrontmatter, toStringOrUndefined } from "./frontmatter"
|
|
6
|
-
import { parseMarkdownToc, type TocHeading } from "./markdown"
|
|
7
|
-
import { tryGetHandler } from "./asset-type-handler"
|
|
8
|
-
|
|
9
|
-
// ── Schema ──────────────────────────────────────────────────────────────────
|
|
10
|
-
|
|
11
|
-
export interface StashIntent {
|
|
12
|
-
when?: string
|
|
13
|
-
input?: string
|
|
14
|
-
output?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface StashEntry {
|
|
18
|
-
name: string
|
|
19
|
-
type: AgentikitAssetType
|
|
20
|
-
description?: string
|
|
21
|
-
tags?: string[]
|
|
22
|
-
examples?: string[]
|
|
23
|
-
intents?: string[]
|
|
24
|
-
intent?: StashIntent
|
|
25
|
-
entry?: string
|
|
26
|
-
generated?: boolean
|
|
27
|
-
quality?: "generated" | "curated"
|
|
28
|
-
confidence?: number
|
|
29
|
-
source?: "package" | "frontmatter" | "comments" | "filename" | "manual" | "llm"
|
|
30
|
-
aliases?: string[]
|
|
31
|
-
toc?: TocHeading[]
|
|
32
|
-
usage?: string[]
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface StashFile {
|
|
36
|
-
entries: StashEntry[]
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ── Load / Write ────────────────────────────────────────────────────────────
|
|
40
|
-
|
|
41
|
-
const STASH_FILENAME = ".stash.json"
|
|
42
|
-
|
|
43
|
-
export function stashFilePath(dirPath: string): string {
|
|
44
|
-
return path.join(dirPath, STASH_FILENAME)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function loadStashFile(dirPath: string): StashFile | null {
|
|
48
|
-
const filePath = stashFilePath(dirPath)
|
|
49
|
-
if (!fs.existsSync(filePath)) return null
|
|
50
|
-
try {
|
|
51
|
-
const raw = JSON.parse(fs.readFileSync(filePath, "utf8"))
|
|
52
|
-
if (!raw || !Array.isArray(raw.entries)) return null
|
|
53
|
-
const entries: StashEntry[] = []
|
|
54
|
-
for (const e of raw.entries) {
|
|
55
|
-
const validated = validateStashEntry(e)
|
|
56
|
-
if (validated) entries.push(validated)
|
|
57
|
-
}
|
|
58
|
-
return entries.length > 0 ? { entries } : null
|
|
59
|
-
} catch {
|
|
60
|
-
return null
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function writeStashFile(dirPath: string, stash: StashFile): void {
|
|
65
|
-
const filePath = stashFilePath(dirPath)
|
|
66
|
-
fs.writeFileSync(filePath, JSON.stringify(stash, null, 2) + "\n", "utf8")
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function validateStashEntry(entry: unknown): StashEntry | null {
|
|
70
|
-
if (typeof entry !== "object" || entry === null) return null
|
|
71
|
-
const e = entry as Record<string, unknown>
|
|
72
|
-
if (typeof e.name !== "string" || !e.name) return null
|
|
73
|
-
if (typeof e.type !== "string" || !isAssetType(e.type)) return null
|
|
74
|
-
|
|
75
|
-
const result: StashEntry = {
|
|
76
|
-
name: e.name,
|
|
77
|
-
type: e.type as AgentikitAssetType,
|
|
78
|
-
}
|
|
79
|
-
if (typeof e.description === "string" && e.description) result.description = e.description
|
|
80
|
-
if (Array.isArray(e.tags)) result.tags = e.tags.filter((t): t is string => typeof t === "string")
|
|
81
|
-
if (Array.isArray(e.examples)) result.examples = e.examples.filter((x): x is string => typeof x === "string")
|
|
82
|
-
if (Array.isArray(e.intents)) {
|
|
83
|
-
const filtered = e.intents.filter((s): s is string => typeof s === "string" && s.trim().length > 0)
|
|
84
|
-
if (filtered.length > 0) result.intents = filtered
|
|
85
|
-
}
|
|
86
|
-
if (typeof e.intent === "object" && e.intent !== null) {
|
|
87
|
-
const intent = e.intent as Record<string, unknown>
|
|
88
|
-
result.intent = {}
|
|
89
|
-
if (typeof intent.when === "string") result.intent.when = intent.when
|
|
90
|
-
if (typeof intent.input === "string") result.intent.input = intent.input
|
|
91
|
-
if (typeof intent.output === "string") result.intent.output = intent.output
|
|
92
|
-
}
|
|
93
|
-
if (typeof e.entry === "string" && e.entry) result.entry = e.entry
|
|
94
|
-
if (e.generated === true) result.generated = true
|
|
95
|
-
if (e.quality === "generated" || e.quality === "curated") result.quality = e.quality
|
|
96
|
-
if (typeof e.confidence === "number" && Number.isFinite(e.confidence)) result.confidence = Math.max(0, Math.min(1, e.confidence))
|
|
97
|
-
if (typeof e.source === "string" && ["package", "frontmatter", "comments", "filename", "manual", "llm"].includes(e.source)) {
|
|
98
|
-
result.source = e.source as StashEntry["source"]
|
|
99
|
-
}
|
|
100
|
-
if (Array.isArray(e.aliases)) {
|
|
101
|
-
const filtered = e.aliases.filter((a): a is string => typeof a === "string" && a.trim().length > 0)
|
|
102
|
-
if (filtered.length > 0) result.aliases = normalizeTerms(filtered)
|
|
103
|
-
}
|
|
104
|
-
if (Array.isArray(e.toc)) {
|
|
105
|
-
const validated = e.toc.filter(
|
|
106
|
-
(h: unknown): h is TocHeading => {
|
|
107
|
-
if (typeof h !== "object" || h === null) return false
|
|
108
|
-
const rec = h as Record<string, unknown>
|
|
109
|
-
return typeof rec.level === "number"
|
|
110
|
-
&& typeof rec.text === "string"
|
|
111
|
-
&& typeof rec.line === "number"
|
|
112
|
-
},
|
|
113
|
-
)
|
|
114
|
-
if (validated.length > 0) result.toc = validated
|
|
115
|
-
}
|
|
116
|
-
const usage = normalizeNonEmptyStringList(e.usage)
|
|
117
|
-
if (usage) result.usage = usage
|
|
118
|
-
|
|
119
|
-
return result
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function normalizeNonEmptyStringList(value: unknown): string[] | undefined {
|
|
123
|
-
if (typeof value === "string") {
|
|
124
|
-
const trimmed = value.trim()
|
|
125
|
-
return trimmed ? [trimmed] : undefined
|
|
126
|
-
}
|
|
127
|
-
if (!Array.isArray(value)) return undefined
|
|
128
|
-
const filtered = value
|
|
129
|
-
.filter((item): item is string => typeof item === "string")
|
|
130
|
-
.map((item) => item.trim())
|
|
131
|
-
.filter((item) => item.length > 0)
|
|
132
|
-
return filtered.length > 0 ? filtered : undefined
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// ── Metadata Generation ─────────────────────────────────────────────────────
|
|
136
|
-
|
|
137
|
-
export function generateMetadata(
|
|
138
|
-
dirPath: string,
|
|
139
|
-
assetType: AgentikitAssetType,
|
|
140
|
-
files: string[],
|
|
141
|
-
typeRoot = dirPath,
|
|
142
|
-
): StashFile {
|
|
143
|
-
const entries: StashEntry[] = []
|
|
144
|
-
const pkgMeta = extractPackageMetadata(dirPath)
|
|
145
|
-
|
|
146
|
-
for (const file of files) {
|
|
147
|
-
const ext = path.extname(file).toLowerCase()
|
|
148
|
-
const baseName = path.basename(file, ext)
|
|
149
|
-
const fileName = path.basename(file)
|
|
150
|
-
|
|
151
|
-
// Skip non-relevant files
|
|
152
|
-
if (!isRelevantAssetFile(assetType, fileName)) continue
|
|
153
|
-
|
|
154
|
-
const canonicalName = assetType === "skill"
|
|
155
|
-
? deriveCanonicalAssetName(assetType, typeRoot, file) ?? baseName
|
|
156
|
-
: baseName
|
|
157
|
-
|
|
158
|
-
const entry: StashEntry = {
|
|
159
|
-
name: canonicalName,
|
|
160
|
-
type: assetType,
|
|
161
|
-
generated: true,
|
|
162
|
-
quality: "generated",
|
|
163
|
-
confidence: 0.55,
|
|
164
|
-
source: "filename",
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Priority 1: package.json metadata
|
|
168
|
-
if (pkgMeta) {
|
|
169
|
-
if (pkgMeta.description && !entry.description) {
|
|
170
|
-
entry.description = pkgMeta.description
|
|
171
|
-
entry.source = "package"
|
|
172
|
-
entry.confidence = 0.8
|
|
173
|
-
}
|
|
174
|
-
if (pkgMeta.keywords && pkgMeta.keywords.length > 0) entry.tags = normalizeTerms(pkgMeta.keywords)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Priority 2: Frontmatter (for .md files — overrides package.json description)
|
|
178
|
-
if (ext === ".md") {
|
|
179
|
-
const fm = extractFrontmatterDescription(file)
|
|
180
|
-
if (fm) {
|
|
181
|
-
entry.description = fm
|
|
182
|
-
entry.source = "frontmatter"
|
|
183
|
-
entry.confidence = 0.9
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Type-specific metadata extraction (e.g. TOC for knowledge, comments for tools/scripts)
|
|
188
|
-
const handler = tryGetHandler(assetType)
|
|
189
|
-
if (handler?.extractTypeMetadata) {
|
|
190
|
-
handler.extractTypeMetadata(entry, file, ext)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Priority 4: Filename heuristics (fallback)
|
|
194
|
-
if (!entry.description) {
|
|
195
|
-
entry.description = fileNameToDescription(baseName)
|
|
196
|
-
entry.source = "filename"
|
|
197
|
-
entry.confidence = Math.min(entry.confidence ?? 0.55, 0.55)
|
|
198
|
-
}
|
|
199
|
-
if (!entry.tags || entry.tags.length === 0) {
|
|
200
|
-
entry.tags = extractTagsFromPath(file, dirPath)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
entry.tags = normalizeTerms(entry.tags ?? [])
|
|
204
|
-
entry.aliases = buildAliases(canonicalName, entry.tags)
|
|
205
|
-
|
|
206
|
-
// Intents are only generated when LLM is configured (via enhanceStashWithLlm)
|
|
207
|
-
// Heuristic intents are too noisy to be useful for search quality
|
|
208
|
-
|
|
209
|
-
entry.entry = path.basename(file)
|
|
210
|
-
entries.push(entry)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return { entries }
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
function normalizeTerms(values: string[]): string[] {
|
|
218
|
-
const normalized = new Set<string>()
|
|
219
|
-
for (const value of values) {
|
|
220
|
-
const cleaned = value.toLowerCase().replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim()
|
|
221
|
-
if (!cleaned) continue
|
|
222
|
-
normalized.add(cleaned)
|
|
223
|
-
if (cleaned.endsWith("s") && cleaned.length > 3) {
|
|
224
|
-
normalized.add(cleaned.slice(0, -1))
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
return Array.from(normalized)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function buildAliases(name: string, tags: string[]): string[] {
|
|
231
|
-
const aliases = new Set<string>()
|
|
232
|
-
const spaced = name.replace(/[-_]+/g, " ").trim().toLowerCase()
|
|
233
|
-
if (spaced && spaced !== name.toLowerCase()) aliases.add(spaced)
|
|
234
|
-
if (tags.length > 1) aliases.add(tags.join(" "))
|
|
235
|
-
return Array.from(aliases)
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export function extractDescriptionFromComments(filePath: string): string | null {
|
|
239
|
-
let content: string
|
|
240
|
-
try {
|
|
241
|
-
content = fs.readFileSync(filePath, "utf8")
|
|
242
|
-
} catch {
|
|
243
|
-
return null
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const lines = content.split(/\r?\n/).slice(0, 50)
|
|
247
|
-
|
|
248
|
-
// Try JSDoc-style block comment: /** ... */
|
|
249
|
-
const blockStart = lines.findIndex((l) => /^\s*\/\*\*/.test(l))
|
|
250
|
-
if (blockStart >= 0) {
|
|
251
|
-
const desc: string[] = []
|
|
252
|
-
for (let i = blockStart; i < lines.length; i++) {
|
|
253
|
-
const line = lines[i]
|
|
254
|
-
if (i > blockStart && /\*\//.test(line)) break
|
|
255
|
-
const cleaned = line.replace(/^\s*\/?\*\*?\s?/, "").replace(/\*\/\s*$/, "").trim()
|
|
256
|
-
if (cleaned) desc.push(cleaned)
|
|
257
|
-
}
|
|
258
|
-
if (desc.length > 0) return desc.join(" ")
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Try hash comments at start of file (skip shebang)
|
|
262
|
-
let start = 0
|
|
263
|
-
if (lines[0]?.startsWith("#!")) start = 1
|
|
264
|
-
const hashLines: string[] = []
|
|
265
|
-
for (let i = start; i < lines.length; i++) {
|
|
266
|
-
const line = lines[i].trim()
|
|
267
|
-
if (line.startsWith("#") && !line.startsWith("#!")) {
|
|
268
|
-
hashLines.push(line.replace(/^#+\s*/, "").trim())
|
|
269
|
-
} else if (line === "") {
|
|
270
|
-
continue
|
|
271
|
-
} else {
|
|
272
|
-
break
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
if (hashLines.length > 0) return hashLines.join(" ")
|
|
276
|
-
|
|
277
|
-
return null
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export function extractFrontmatterDescription(filePath: string): string | null {
|
|
281
|
-
let content: string
|
|
282
|
-
try {
|
|
283
|
-
content = fs.readFileSync(filePath, "utf8")
|
|
284
|
-
} catch {
|
|
285
|
-
return null
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const parsed = parseFrontmatter(content)
|
|
289
|
-
return toStringOrUndefined(parsed.data.description) ?? null
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
export function extractPackageMetadata(
|
|
293
|
-
dirPath: string,
|
|
294
|
-
): { name?: string; description?: string; keywords?: string[] } | null {
|
|
295
|
-
const pkgPath = path.join(dirPath, "package.json")
|
|
296
|
-
if (!fs.existsSync(pkgPath)) return null
|
|
297
|
-
try {
|
|
298
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"))
|
|
299
|
-
const result: { name?: string; description?: string; keywords?: string[] } = {}
|
|
300
|
-
if (typeof pkg.name === "string") result.name = pkg.name
|
|
301
|
-
if (typeof pkg.description === "string") result.description = pkg.description
|
|
302
|
-
if (Array.isArray(pkg.keywords)) {
|
|
303
|
-
result.keywords = pkg.keywords.filter((k: unknown): k is string => typeof k === "string")
|
|
304
|
-
}
|
|
305
|
-
return Object.keys(result).length > 0 ? result : null
|
|
306
|
-
} catch {
|
|
307
|
-
return null
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
export function fileNameToDescription(fileName: string): string {
|
|
312
|
-
return fileName
|
|
313
|
-
.replace(/[-_]+/g, " ")
|
|
314
|
-
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
315
|
-
.toLowerCase()
|
|
316
|
-
.trim()
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
export function extractTagsFromPath(filePath: string, rootDir: string): string[] {
|
|
320
|
-
const rel = path.relative(rootDir, filePath)
|
|
321
|
-
const parts = rel.split(path.sep)
|
|
322
|
-
const tags = new Set<string>()
|
|
323
|
-
|
|
324
|
-
for (const part of parts) {
|
|
325
|
-
const name = part.replace(path.extname(part), "")
|
|
326
|
-
for (const token of name.split(/[-_./\\]+/)) {
|
|
327
|
-
const clean = token.toLowerCase().trim()
|
|
328
|
-
if (clean && clean.length > 1) tags.add(clean)
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return Array.from(tags)
|
|
333
|
-
}
|
package/src/origin-resolve.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import path from "node:path"
|
|
2
|
-
import type { StashSource } from "./stash-source"
|
|
3
|
-
import { parseRegistryRef } from "./registry-resolve"
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Given an origin string (from an AssetRef) and the full list of stash
|
|
7
|
-
* sources, return the subset of sources to search.
|
|
8
|
-
*
|
|
9
|
-
* Resolution order:
|
|
10
|
-
* 1. undefined → all sources (working → mounted → installed)
|
|
11
|
-
* 2. "local" → working stash only
|
|
12
|
-
* 3. exact match → installed source whose registryId matches verbatim
|
|
13
|
-
* 4. parsed match → parse origin as a registry ref, match by parsed ID
|
|
14
|
-
* 5. path match → mounted source whose path matches
|
|
15
|
-
* 6. empty → indicates a remote/uninstalled origin (caller decides)
|
|
16
|
-
*/
|
|
17
|
-
export function resolveSourcesForOrigin(
|
|
18
|
-
origin: string | undefined,
|
|
19
|
-
allSources: StashSource[],
|
|
20
|
-
): StashSource[] {
|
|
21
|
-
if (!origin) return allSources
|
|
22
|
-
|
|
23
|
-
if (origin === "local") {
|
|
24
|
-
return allSources.filter((s) => s.kind === "working")
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Exact registryId match (e.g. origin is "npm:@scope/pkg")
|
|
28
|
-
const byExactId = allSources.filter(
|
|
29
|
-
(s) => s.kind === "installed" && s.registryId === origin,
|
|
30
|
-
)
|
|
31
|
-
if (byExactId.length > 0) return byExactId
|
|
32
|
-
|
|
33
|
-
// Parse origin as a registry ref and match by parsed ID.
|
|
34
|
-
// Allows shorthand: "owner/repo" matches "github:owner/repo",
|
|
35
|
-
// "@scope/pkg" matches "npm:@scope/pkg".
|
|
36
|
-
try {
|
|
37
|
-
const parsed = parseRegistryRef(origin)
|
|
38
|
-
const byParsedId = allSources.filter(
|
|
39
|
-
(s) => s.kind === "installed" && s.registryId === parsed.id,
|
|
40
|
-
)
|
|
41
|
-
if (byParsedId.length > 0) return byParsedId
|
|
42
|
-
} catch {
|
|
43
|
-
// Not a valid registry ref — continue to path matching
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Mounted stash by resolved path
|
|
47
|
-
const resolvedOrigin = path.resolve(origin)
|
|
48
|
-
const byPath = allSources.filter(
|
|
49
|
-
(s) => s.kind === "mounted" && path.resolve(s.path) === resolvedOrigin,
|
|
50
|
-
)
|
|
51
|
-
if (byPath.length > 0) return byPath
|
|
52
|
-
|
|
53
|
-
// No match — origin may be remote/uninstalled
|
|
54
|
-
return []
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Check whether an origin refers to something that could be fetched remotely
|
|
59
|
-
* (i.e. it looks like a registry ref but isn't installed locally).
|
|
60
|
-
*/
|
|
61
|
-
export function isRemoteOrigin(
|
|
62
|
-
origin: string,
|
|
63
|
-
allSources: StashSource[],
|
|
64
|
-
): boolean {
|
|
65
|
-
if (origin === "local") return false
|
|
66
|
-
return resolveSourcesForOrigin(origin, allSources).length === 0
|
|
67
|
-
}
|