akm-cli 0.5.0 → 0.6.0-rc2
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/CHANGELOG.md +53 -5
- package/README.md +9 -9
- package/dist/cli.js +379 -1448
- package/dist/{completions.js → commands/completions.js} +1 -1
- package/dist/{config-cli.js → commands/config-cli.js} +109 -11
- package/dist/commands/curate.js +263 -0
- package/dist/{info.js → commands/info.js} +17 -11
- package/dist/{init.js → commands/init.js} +4 -4
- package/dist/{install-audit.js → commands/install-audit.js} +14 -2
- package/dist/{installed-kits.js → commands/installed-stashes.js} +122 -50
- package/dist/commands/migration-help.js +141 -0
- package/dist/{registry-search.js → commands/registry-search.js} +68 -9
- package/dist/commands/remember.js +178 -0
- package/dist/{stash-search.js → commands/search.js} +28 -69
- package/dist/{self-update.js → commands/self-update.js} +3 -3
- package/dist/{stash-show.js → commands/show.js} +106 -81
- package/dist/{stash-add.js → commands/source-add.js} +133 -67
- package/dist/{stash-clone.js → commands/source-clone.js} +15 -13
- package/dist/{stash-source-manage.js → commands/source-manage.js} +24 -24
- package/dist/{vault.js → commands/vault.js} +43 -0
- package/dist/{stash-ref.js → core/asset-ref.js} +4 -4
- package/dist/{asset-registry.js → core/asset-registry.js} +30 -6
- package/dist/{asset-spec.js → core/asset-spec.js} +13 -6
- package/dist/{common.js → core/common.js} +147 -50
- package/dist/{config.js → core/config.js} +288 -29
- package/dist/core/errors.js +90 -0
- package/dist/{frontmatter.js → core/frontmatter.js} +64 -8
- package/dist/{paths.js → core/paths.js} +4 -4
- package/dist/core/write-source.js +280 -0
- package/dist/{local-search.js → indexer/db-search.js} +49 -32
- package/dist/{db.js → indexer/db.js} +210 -81
- package/dist/{file-context.js → indexer/file-context.js} +3 -3
- package/dist/{indexer.js → indexer/indexer.js} +153 -30
- package/dist/{manifest.js → indexer/manifest.js} +10 -10
- package/dist/{matchers.js → indexer/matchers.js} +4 -7
- package/dist/{metadata.js → indexer/metadata.js} +9 -5
- package/dist/{search-source.js → indexer/search-source.js} +97 -55
- package/dist/{semantic-status.js → indexer/semantic-status.js} +2 -2
- package/dist/{walker.js → indexer/walker.js} +1 -1
- package/dist/{lockfile.js → integrations/lockfile.js} +29 -2
- package/dist/{llm.js → llm/client.js} +12 -48
- package/dist/llm/embedder.js +127 -0
- package/dist/llm/embedders/cache.js +47 -0
- package/dist/llm/embedders/local.js +152 -0
- package/dist/llm/embedders/remote.js +121 -0
- package/dist/llm/embedders/types.js +39 -0
- package/dist/llm/metadata-enhance.js +53 -0
- package/dist/output/cli-hints.js +301 -0
- package/dist/output/context.js +95 -0
- package/dist/{renderers.js → output/renderers.js} +57 -61
- package/dist/output/shapes.js +212 -0
- package/dist/output/text.js +520 -0
- package/dist/{registry-build-index.js → registry/build-index.js} +48 -32
- package/dist/{create-provider-registry.js → registry/create-provider-registry.js} +6 -2
- package/dist/registry/factory.js +33 -0
- package/dist/{origin-resolve.js → registry/origin-resolve.js} +1 -1
- package/dist/registry/providers/index.js +11 -0
- package/dist/{providers → registry/providers}/skills-sh.js +60 -4
- package/dist/{providers → registry/providers}/static-index.js +126 -56
- package/dist/registry/providers/types.js +25 -0
- package/dist/{registry-resolve.js → registry/resolve.js} +10 -6
- package/dist/{detect.js → setup/detect.js} +0 -27
- package/dist/{ripgrep-install.js → setup/ripgrep-install.js} +1 -1
- package/dist/{ripgrep-resolve.js → setup/ripgrep-resolve.js} +2 -2
- package/dist/{setup.js → setup/setup.js} +162 -129
- package/dist/setup/steps.js +45 -0
- package/dist/{kit-include.js → sources/include.js} +1 -1
- package/dist/sources/provider-factory.js +36 -0
- package/dist/sources/provider.js +21 -0
- package/dist/sources/providers/filesystem.js +35 -0
- package/dist/{stash-providers → sources/providers}/git.js +218 -28
- package/dist/{stash-providers → sources/providers}/index.js +4 -4
- package/dist/sources/providers/install-types.js +14 -0
- package/dist/sources/providers/npm.js +160 -0
- package/dist/sources/providers/provider-utils.js +173 -0
- package/dist/sources/providers/sync-from-ref.js +45 -0
- package/dist/sources/providers/tar-utils.js +154 -0
- package/dist/{stash-providers → sources/providers}/website.js +60 -20
- package/dist/{stash-resolve.js → sources/resolve.js} +13 -12
- package/dist/{wiki.js → wiki/wiki.js} +18 -17
- package/dist/{workflow-authoring.js → workflows/authoring.js} +48 -17
- package/dist/{workflow-cli.js → workflows/cli.js} +2 -1
- package/dist/{workflow-db.js → workflows/db.js} +1 -1
- package/dist/workflows/document-cache.js +20 -0
- package/dist/workflows/parser.js +379 -0
- package/dist/workflows/renderer.js +78 -0
- package/dist/{workflow-runs.js → workflows/runs.js} +84 -30
- package/dist/workflows/schema.js +11 -0
- package/dist/workflows/validator.js +48 -0
- package/docs/README.md +30 -0
- package/docs/migration/release-notes/0.0.13.md +4 -0
- package/docs/migration/release-notes/0.1.0.md +6 -0
- package/docs/migration/release-notes/0.2.0.md +6 -0
- package/docs/migration/release-notes/0.3.0.md +5 -0
- package/docs/migration/release-notes/0.5.0.md +6 -0
- package/docs/migration/release-notes/0.6.0.md +75 -0
- package/docs/migration/release-notes/README.md +21 -0
- package/package.json +3 -2
- package/dist/embedder.js +0 -351
- package/dist/errors.js +0 -34
- package/dist/migration-help.js +0 -110
- package/dist/registry-factory.js +0 -19
- package/dist/registry-install.js +0 -532
- package/dist/ripgrep.js +0 -2
- package/dist/stash-provider-factory.js +0 -35
- package/dist/stash-provider.js +0 -1
- package/dist/stash-providers/filesystem.js +0 -41
- package/dist/stash-providers/openviking.js +0 -348
- package/dist/stash-providers/provider-utils.js +0 -11
- package/dist/stash-types.js +0 -1
- package/dist/workflow-markdown.js +0 -251
- /package/dist/{markdown.js → core/markdown.js} +0 -0
- /package/dist/{warn.js → core/warn.js} +0 -0
- /package/dist/{search-fields.js → indexer/search-fields.js} +0 -0
- /package/dist/{usage-events.js → indexer/usage-events.js} +0 -0
- /package/dist/{github.js → integrations/github.js} +0 -0
- /package/dist/{registry-provider.js → registry/types.js} +0 -0
- /package/dist/{registry-types.js → sources/types.js} +0 -0
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import { parseFrontmatter, toStringOrUndefined } from "./frontmatter";
|
|
2
|
-
const ALLOWED_FRONTMATTER_KEYS = new Set(["description", "tags", "params"]);
|
|
3
|
-
const STEP_ID_REGEX = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
4
|
-
export class WorkflowValidationError extends Error {
|
|
5
|
-
constructor(message) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.name = "WorkflowValidationError";
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
export function parseWorkflowMarkdown(markdown) {
|
|
11
|
-
const parsed = parseFrontmatter(markdown);
|
|
12
|
-
validateFrontmatter(parsed.data);
|
|
13
|
-
const title = extractWorkflowTitle(parsed.content);
|
|
14
|
-
const parameters = extractWorkflowParameters(parsed.data);
|
|
15
|
-
const tags = extractWorkflowTags(parsed.data, parsed.frontmatter);
|
|
16
|
-
const steps = extractWorkflowSteps(parsed.content);
|
|
17
|
-
return {
|
|
18
|
-
title,
|
|
19
|
-
description: toStringOrUndefined(parsed.data.description),
|
|
20
|
-
...(tags ? { tags } : {}),
|
|
21
|
-
...(parameters ? { parameters } : {}),
|
|
22
|
-
steps,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
function validateFrontmatter(data) {
|
|
26
|
-
const unsupported = Object.keys(data).filter((key) => !ALLOWED_FRONTMATTER_KEYS.has(key));
|
|
27
|
-
if (unsupported.length > 0) {
|
|
28
|
-
throw new WorkflowValidationError(`Workflow frontmatter only supports description, tags, and params. Unsupported key(s): ${unsupported.join(", ")}`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
function extractWorkflowTitle(body) {
|
|
32
|
-
const matches = Array.from(body.matchAll(/^#\s+Workflow:\s+(.+?)\s*$/gm));
|
|
33
|
-
if (matches.length === 0) {
|
|
34
|
-
throw new WorkflowValidationError('Workflow markdown must contain a "# Workflow: <title>" heading.');
|
|
35
|
-
}
|
|
36
|
-
if (matches.length > 1) {
|
|
37
|
-
throw new WorkflowValidationError('Workflow markdown must contain exactly one "# Workflow: <title>" heading.');
|
|
38
|
-
}
|
|
39
|
-
const title = matches[0]?.[1]?.trim() ?? "";
|
|
40
|
-
if (!title) {
|
|
41
|
-
throw new WorkflowValidationError('Workflow markdown must contain a non-empty "# Workflow: <title>" heading.');
|
|
42
|
-
}
|
|
43
|
-
return title;
|
|
44
|
-
}
|
|
45
|
-
function extractWorkflowTags(data, frontmatter) {
|
|
46
|
-
const tags = data.tags;
|
|
47
|
-
if (typeof tags === "undefined")
|
|
48
|
-
return undefined;
|
|
49
|
-
if (typeof tags === "string") {
|
|
50
|
-
const trimmed = tags.trim();
|
|
51
|
-
return trimmed ? [trimmed] : undefined;
|
|
52
|
-
}
|
|
53
|
-
if (frontmatter &&
|
|
54
|
-
typeof tags === "object" &&
|
|
55
|
-
tags !== null &&
|
|
56
|
-
!Array.isArray(tags) &&
|
|
57
|
-
Object.keys(tags).length === 0) {
|
|
58
|
-
const blockTags = extractTagListFromFrontmatter(frontmatter);
|
|
59
|
-
if (blockTags)
|
|
60
|
-
return blockTags;
|
|
61
|
-
}
|
|
62
|
-
if (!Array.isArray(tags) || !tags.every((tag) => typeof tag === "string" && tag.trim().length > 0)) {
|
|
63
|
-
throw new WorkflowValidationError("Workflow frontmatter `tags` must be a string or an array of non-empty strings.");
|
|
64
|
-
}
|
|
65
|
-
return tags.map((tag) => tag.trim());
|
|
66
|
-
}
|
|
67
|
-
function extractWorkflowParameters(data) {
|
|
68
|
-
const params = data.params;
|
|
69
|
-
if (typeof params === "undefined")
|
|
70
|
-
return undefined;
|
|
71
|
-
if (typeof params !== "object" || params === null || Array.isArray(params)) {
|
|
72
|
-
throw new WorkflowValidationError("Workflow frontmatter `params` must be a mapping of parameter names to descriptions.");
|
|
73
|
-
}
|
|
74
|
-
const entries = Object.entries(params);
|
|
75
|
-
if (entries.length === 0)
|
|
76
|
-
return undefined;
|
|
77
|
-
return entries.map(([name, description]) => {
|
|
78
|
-
if (!name.trim()) {
|
|
79
|
-
throw new WorkflowValidationError("Workflow parameter names must be non-empty.");
|
|
80
|
-
}
|
|
81
|
-
if (typeof description !== "string" || !description.trim()) {
|
|
82
|
-
throw new WorkflowValidationError(`Workflow parameter "${name}" must have a non-empty string description in frontmatter params.`);
|
|
83
|
-
}
|
|
84
|
-
return { name: name.trim(), description: description.trim() };
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
function extractWorkflowSteps(body) {
|
|
88
|
-
const lines = normalizeLines(body);
|
|
89
|
-
const titleLineIndex = lines.findIndex((line) => /^#\s+Workflow:\s+/.test(line));
|
|
90
|
-
if (titleLineIndex === -1) {
|
|
91
|
-
throw new WorkflowValidationError('Workflow markdown must contain a "# Workflow: <title>" heading.');
|
|
92
|
-
}
|
|
93
|
-
const steps = [];
|
|
94
|
-
let index = titleLineIndex + 1;
|
|
95
|
-
while (index < lines.length) {
|
|
96
|
-
const line = lines[index] ?? "";
|
|
97
|
-
const trimmed = line.trim();
|
|
98
|
-
if (!trimmed) {
|
|
99
|
-
index++;
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
if (trimmed.startsWith("# ") && !/^#\s+Workflow:\s+/.test(trimmed)) {
|
|
103
|
-
throw new WorkflowValidationError(`Unexpected top-level heading after workflow title: "${trimmed}".`);
|
|
104
|
-
}
|
|
105
|
-
const stepHeader = trimmed.match(/^##\s+Step:\s+(.+?)\s*$/);
|
|
106
|
-
if (!stepHeader) {
|
|
107
|
-
throw new WorkflowValidationError(`Expected a "## Step: <title>" section after the workflow title, but found: "${trimmed}".`);
|
|
108
|
-
}
|
|
109
|
-
const stepTitle = stepHeader[1].trim();
|
|
110
|
-
const sequenceIndex = steps.length;
|
|
111
|
-
index++;
|
|
112
|
-
let stepId;
|
|
113
|
-
let instructions;
|
|
114
|
-
let completionCriteria;
|
|
115
|
-
while (index < lines.length) {
|
|
116
|
-
const current = lines[index] ?? "";
|
|
117
|
-
const currentTrimmed = current.trim();
|
|
118
|
-
if (/^##\s+Step:\s+/.test(currentTrimmed))
|
|
119
|
-
break;
|
|
120
|
-
if (/^#\s+/.test(currentTrimmed)) {
|
|
121
|
-
throw new WorkflowValidationError(`Unexpected heading "${currentTrimmed}" inside step "${stepTitle}". Only step sections and step subsections are allowed.`);
|
|
122
|
-
}
|
|
123
|
-
if (!currentTrimmed) {
|
|
124
|
-
index++;
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
const stepIdMatch = currentTrimmed.match(/^Step ID:\s+(.+?)\s*$/);
|
|
128
|
-
if (stepIdMatch) {
|
|
129
|
-
if (stepId) {
|
|
130
|
-
throw new WorkflowValidationError(`Step "${stepTitle}" must contain exactly one "Step ID: <id>" line.`);
|
|
131
|
-
}
|
|
132
|
-
stepId = stepIdMatch[1].trim();
|
|
133
|
-
if (!STEP_ID_REGEX.test(stepId)) {
|
|
134
|
-
throw new WorkflowValidationError(`Step "${stepTitle}" has invalid Step ID "${stepId}". Use letters, numbers, ".", "_" or "-".`);
|
|
135
|
-
}
|
|
136
|
-
index++;
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
const subsection = currentTrimmed.match(/^###\s+(.+?)\s*$/);
|
|
140
|
-
if (!subsection) {
|
|
141
|
-
throw new WorkflowValidationError(`Unexpected content in step "${stepTitle}". Add "Step ID: <id>" before subsections or move text under "### Instructions".`);
|
|
142
|
-
}
|
|
143
|
-
const subsectionName = subsection[1].trim();
|
|
144
|
-
index++;
|
|
145
|
-
const block = collectSectionBlock(lines, index);
|
|
146
|
-
index = block.nextIndex;
|
|
147
|
-
if (subsectionName === "Instructions") {
|
|
148
|
-
if (instructions) {
|
|
149
|
-
throw new WorkflowValidationError(`Step "${stepTitle}" must contain exactly one "### Instructions" section.`);
|
|
150
|
-
}
|
|
151
|
-
instructions = block.text;
|
|
152
|
-
if (!instructions) {
|
|
153
|
-
throw new WorkflowValidationError(`Step "${stepTitle}" must include instructions text.`);
|
|
154
|
-
}
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
if (subsectionName === "Completion Criteria") {
|
|
158
|
-
if (completionCriteria) {
|
|
159
|
-
throw new WorkflowValidationError(`Step "${stepTitle}" must contain at most one "### Completion Criteria" section.`);
|
|
160
|
-
}
|
|
161
|
-
completionCriteria = block.items;
|
|
162
|
-
if (!completionCriteria || completionCriteria.length === 0) {
|
|
163
|
-
throw new WorkflowValidationError(`Step "${stepTitle}" has an empty "### Completion Criteria" section.`);
|
|
164
|
-
}
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
throw new WorkflowValidationError(`Unknown subsection "### ${subsectionName}" in step "${stepTitle}". Only "### Instructions" and optional "### Completion Criteria" are supported.`);
|
|
168
|
-
}
|
|
169
|
-
if (!stepId) {
|
|
170
|
-
throw new WorkflowValidationError(`Step "${stepTitle}" must contain exactly one "Step ID: <id>" line.`);
|
|
171
|
-
}
|
|
172
|
-
if (!instructions) {
|
|
173
|
-
throw new WorkflowValidationError(`Step "${stepTitle}" must contain a "### Instructions" section.`);
|
|
174
|
-
}
|
|
175
|
-
steps.push({
|
|
176
|
-
id: stepId,
|
|
177
|
-
title: stepTitle,
|
|
178
|
-
instructions,
|
|
179
|
-
...(completionCriteria ? { completionCriteria } : {}),
|
|
180
|
-
sequenceIndex,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
if (steps.length === 0) {
|
|
184
|
-
throw new WorkflowValidationError('Workflow markdown must contain at least one "## Step: <title>" section.');
|
|
185
|
-
}
|
|
186
|
-
const seenStepIds = new Set();
|
|
187
|
-
for (const step of steps) {
|
|
188
|
-
if (seenStepIds.has(step.id)) {
|
|
189
|
-
throw new WorkflowValidationError(`Workflow step IDs must be unique. Duplicate Step ID: "${step.id}".`);
|
|
190
|
-
}
|
|
191
|
-
seenStepIds.add(step.id);
|
|
192
|
-
}
|
|
193
|
-
return steps;
|
|
194
|
-
}
|
|
195
|
-
function normalizeLines(body) {
|
|
196
|
-
return body.replace(/\r\n|\r/g, "\n").split("\n");
|
|
197
|
-
}
|
|
198
|
-
function collectSectionBlock(lines, startIndex) {
|
|
199
|
-
const collected = [];
|
|
200
|
-
let index = startIndex;
|
|
201
|
-
while (index < lines.length) {
|
|
202
|
-
const line = lines[index] ?? "";
|
|
203
|
-
const trimmed = line.trim();
|
|
204
|
-
if (/^##\s+Step:\s+/.test(trimmed) || /^###\s+/.test(trimmed) || /^#\s+/.test(trimmed))
|
|
205
|
-
break;
|
|
206
|
-
collected.push(line);
|
|
207
|
-
index++;
|
|
208
|
-
}
|
|
209
|
-
const text = collected.join("\n").trim();
|
|
210
|
-
const items = text
|
|
211
|
-
? text
|
|
212
|
-
.split("\n")
|
|
213
|
-
.map((line) => line.trim())
|
|
214
|
-
.filter(Boolean)
|
|
215
|
-
.map((line) => line.replace(/^[-*]\s*/, "").trim())
|
|
216
|
-
.filter(Boolean)
|
|
217
|
-
: undefined;
|
|
218
|
-
return { text, items, nextIndex: index };
|
|
219
|
-
}
|
|
220
|
-
function extractTagListFromFrontmatter(frontmatter) {
|
|
221
|
-
const lines = frontmatter.split("\n");
|
|
222
|
-
const tagIndex = lines.findIndex((line) => /^tags:\s*$/.test(line.trim()));
|
|
223
|
-
if (tagIndex === -1)
|
|
224
|
-
return undefined;
|
|
225
|
-
const tags = [];
|
|
226
|
-
for (let index = tagIndex + 1; index < lines.length; index++) {
|
|
227
|
-
const line = lines[index] ?? "";
|
|
228
|
-
const trimmed = line.trim();
|
|
229
|
-
if (!trimmed)
|
|
230
|
-
continue;
|
|
231
|
-
if (!line.startsWith(" "))
|
|
232
|
-
break;
|
|
233
|
-
const match = trimmed.match(/^-\s+(.+?)\s*$/);
|
|
234
|
-
if (!match) {
|
|
235
|
-
throw new WorkflowValidationError("Workflow frontmatter `tags` must contain only dash-prefixed list items when declared as a block list.");
|
|
236
|
-
}
|
|
237
|
-
const tag = stripMatchingQuotes(match[1]?.trim() ?? "");
|
|
238
|
-
if (tag)
|
|
239
|
-
tags.push(tag);
|
|
240
|
-
}
|
|
241
|
-
return tags.length > 0 ? tags : undefined;
|
|
242
|
-
}
|
|
243
|
-
function stripMatchingQuotes(value) {
|
|
244
|
-
if (value.length >= 2) {
|
|
245
|
-
const quote = value[0];
|
|
246
|
-
if ((quote === '"' || quote === "'") && value[value.length - 1] === quote) {
|
|
247
|
-
return value.slice(1, -1).trim();
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return value;
|
|
251
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|