kontexted 0.1.10 → 0.1.11
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/dist/commands/skill.js +71 -1
- package/dist/skill-init/providers/base.d.ts +19 -3
- package/dist/skill-init/providers/opencode.js +14 -7
- package/dist/skill-init/templates/kontexted-cli.js +61 -70
- package/dist/skill-init/utils.d.ts +4 -0
- package/dist/skill-init/utils.js +16 -6
- package/package.json +4 -4
package/dist/commands/skill.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as readline from "readline";
|
|
2
2
|
import { readConfig, writeConfig } from "../lib/config.js";
|
|
3
|
-
import { getProfile } from "../lib/profile.js";
|
|
3
|
+
import { getProfile, listProfiles } from "../lib/profile.js";
|
|
4
4
|
import { ApiClient } from "../lib/api-client.js";
|
|
5
5
|
import { ensureValidTokens } from "../lib/oauth.js";
|
|
6
6
|
import { getProvider, allTemplates } from "../skill-init/index.js";
|
|
@@ -117,6 +117,51 @@ async function createApiClient(alias) {
|
|
|
117
117
|
function displayResult(result) {
|
|
118
118
|
console.log(JSON.stringify(result, null, 2));
|
|
119
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Interactive profile selection for skill init
|
|
122
|
+
* Returns { alias, hasWrite } or null if user chose generic
|
|
123
|
+
*/
|
|
124
|
+
async function selectProfile(profiles) {
|
|
125
|
+
// Build choices array
|
|
126
|
+
const choices = profiles.map(({ alias, profile }) => ({
|
|
127
|
+
alias,
|
|
128
|
+
hasWrite: profile.write,
|
|
129
|
+
label: `${alias} (write: ${profile.write ? '✓' : '✗'})`,
|
|
130
|
+
}));
|
|
131
|
+
// Add option to skip
|
|
132
|
+
choices.push({
|
|
133
|
+
alias: '',
|
|
134
|
+
hasWrite: false,
|
|
135
|
+
label: '[Skip - use generic template]',
|
|
136
|
+
});
|
|
137
|
+
console.log('\nSelect a profile to embed in kontexted-cli skill:\n');
|
|
138
|
+
choices.forEach((choice, index) => {
|
|
139
|
+
const marker = index === 0 ? '❯' : ' ';
|
|
140
|
+
console.log(` ${marker} ${index + 1}. ${choice.label}`);
|
|
141
|
+
});
|
|
142
|
+
const rl = readline.createInterface({
|
|
143
|
+
input: process.stdin,
|
|
144
|
+
output: process.stdout,
|
|
145
|
+
});
|
|
146
|
+
return new Promise((resolve) => {
|
|
147
|
+
rl.question('\nEnter selection (1-' + choices.length + '): ', (answer) => {
|
|
148
|
+
rl.close();
|
|
149
|
+
const selection = parseInt(answer.trim(), 10);
|
|
150
|
+
if (isNaN(selection) || selection < 1 || selection > choices.length) {
|
|
151
|
+
console.log('Invalid selection, using generic template.');
|
|
152
|
+
resolve(null);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const chosen = choices[selection - 1];
|
|
156
|
+
if (!chosen.alias) {
|
|
157
|
+
// User chose "Skip - use generic"
|
|
158
|
+
resolve(null);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
resolve({ alias: chosen.alias, hasWrite: chosen.hasWrite });
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
120
165
|
/**
|
|
121
166
|
* Register the skill command and its subcommands
|
|
122
167
|
*/
|
|
@@ -279,6 +324,7 @@ export function registerSkillCommand(program) {
|
|
|
279
324
|
.description("Initialize AI agent skills for the current project")
|
|
280
325
|
.option("--provider <name>", "Provider to use (default: opencode)", "opencode")
|
|
281
326
|
.option("--all", "Generate all available skills without prompting", false)
|
|
327
|
+
.option("--no-prompt", "Skip profile selection, use generic template", false)
|
|
282
328
|
.action(async (options) => {
|
|
283
329
|
try {
|
|
284
330
|
// Get the provider
|
|
@@ -291,6 +337,28 @@ export function registerSkillCommand(program) {
|
|
|
291
337
|
console.error(`Available providers: ${["opencode"].join(", ")}`);
|
|
292
338
|
process.exit(1);
|
|
293
339
|
}
|
|
340
|
+
// Resolve alias and write permissions through interactive selection
|
|
341
|
+
let alias;
|
|
342
|
+
let hasWrite = false;
|
|
343
|
+
if (!options.noPrompt) {
|
|
344
|
+
const config = await readConfig();
|
|
345
|
+
const profiles = listProfiles(config);
|
|
346
|
+
if (profiles.length > 0) {
|
|
347
|
+
const selection = await selectProfile(profiles);
|
|
348
|
+
if (selection) {
|
|
349
|
+
alias = selection.alias;
|
|
350
|
+
hasWrite = selection.hasWrite;
|
|
351
|
+
console.log(`\nUsing profile: ${alias} (write: ${hasWrite})\n`);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
console.log('\nUsing generic template (no alias)\n');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
console.log('No profiles found. Using generic template.\n');
|
|
359
|
+
console.log('To create a profile, run: kontexted login --alias <name> --url <url> --workspace <slug>\n');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
294
362
|
// Show what will be generated
|
|
295
363
|
console.log(`This will generate the following skills for ${provider.name}:`);
|
|
296
364
|
for (const template of allTemplates) {
|
|
@@ -321,6 +389,8 @@ export function registerSkillCommand(program) {
|
|
|
321
389
|
const result = await initSkill({
|
|
322
390
|
skill: template,
|
|
323
391
|
provider,
|
|
392
|
+
alias,
|
|
393
|
+
hasWrite,
|
|
324
394
|
});
|
|
325
395
|
const status = result.created ? "Created" : "Updated";
|
|
326
396
|
console.log(`✓ ${status} ${result.path}`);
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options passed to skill content generator functions
|
|
3
|
+
*/
|
|
4
|
+
export interface SkillContentOptions {
|
|
5
|
+
/** Profile alias to substitute in commands */
|
|
6
|
+
alias?: string;
|
|
7
|
+
/** Whether the profile has write permissions */
|
|
8
|
+
hasWrite: boolean;
|
|
9
|
+
}
|
|
1
10
|
/**
|
|
2
11
|
* Definition of a skill to be generated
|
|
3
12
|
*/
|
|
@@ -6,8 +15,15 @@ export interface SkillDefinition {
|
|
|
6
15
|
name: string;
|
|
7
16
|
/** Short description (1-1024 characters) */
|
|
8
17
|
description: string;
|
|
9
|
-
/**
|
|
10
|
-
content: string;
|
|
18
|
+
/** Static content string OR content generator function that receives options */
|
|
19
|
+
content: string | ((options: SkillContentOptions) => string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Options for skill content generation
|
|
23
|
+
*/
|
|
24
|
+
export interface GenerateContentOptions {
|
|
25
|
+
/** Optional alias to include in frontmatter */
|
|
26
|
+
alias?: string;
|
|
11
27
|
}
|
|
12
28
|
/**
|
|
13
29
|
* Provider interface for different AI agent platforms
|
|
@@ -22,5 +38,5 @@ export interface SkillProvider {
|
|
|
22
38
|
/** Validate skill name according to provider rules */
|
|
23
39
|
validateSkillName(name: string): boolean;
|
|
24
40
|
/** Generate the complete skill file content including frontmatter */
|
|
25
|
-
generateSkillContent(skill: SkillDefinition): string;
|
|
41
|
+
generateSkillContent(skill: SkillDefinition, resolvedContent: string, options?: GenerateContentOptions): string;
|
|
26
42
|
}
|
|
@@ -33,16 +33,23 @@ export const opencodeProvider = {
|
|
|
33
33
|
},
|
|
34
34
|
/**
|
|
35
35
|
* Generate the complete skill file content including frontmatter
|
|
36
|
-
* @param skill - The skill definition
|
|
36
|
+
* @param skill - The skill definition (for name and description)
|
|
37
|
+
* @param resolvedContent - The resolved content string (after generator function if applicable)
|
|
38
|
+
* @param options - Optional metadata to include in frontmatter
|
|
37
39
|
* @returns The complete markdown content with frontmatter
|
|
38
40
|
*/
|
|
39
|
-
generateSkillContent(skill) {
|
|
40
|
-
const
|
|
41
|
-
name: ${skill.name}
|
|
42
|
-
description: ${skill.description}
|
|
43
|
-
|
|
41
|
+
generateSkillContent(skill, resolvedContent, options) {
|
|
42
|
+
const frontmatterLines = [
|
|
43
|
+
`name: ${skill.name}`,
|
|
44
|
+
`description: ${skill.description}`,
|
|
45
|
+
];
|
|
46
|
+
// Add alias to frontmatter if provided
|
|
47
|
+
if (options?.alias) {
|
|
48
|
+
frontmatterLines.push(`alias: ${options.alias}`);
|
|
49
|
+
}
|
|
50
|
+
const frontmatter = `---\n${frontmatterLines.join('\n')}\n---`;
|
|
44
51
|
return `${frontmatter}
|
|
45
52
|
|
|
46
|
-
${
|
|
53
|
+
${resolvedContent}`;
|
|
47
54
|
}
|
|
48
55
|
};
|
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Generate kontexted-cli skill content based on profile settings
|
|
3
|
+
*/
|
|
4
|
+
function generateKontextedCliContent(options) {
|
|
5
|
+
const { alias, hasWrite } = options;
|
|
6
|
+
// Use actual alias or generic placeholder
|
|
7
|
+
const a = alias || '<profile>';
|
|
8
|
+
return String.raw `# Kontexted CLI Skill Commands
|
|
5
9
|
|
|
6
|
-
## Read Commands
|
|
10
|
+
## Read Commands
|
|
7
11
|
|
|
8
12
|
\`\`\`
|
|
9
|
-
kontexted skill workspace-tree --alias
|
|
10
|
-
kontexted skill search-notes --alias
|
|
11
|
-
kontexted skill note-by-id --alias
|
|
13
|
+
kontexted skill workspace-tree --alias ${a}
|
|
14
|
+
kontexted skill search-notes --alias ${a} --query "<text>" [--limit <n>]
|
|
15
|
+
kontexted skill note-by-id --alias ${a} --note-id <id>
|
|
12
16
|
\`\`\`
|
|
13
|
-
|
|
14
|
-
## Write Commands
|
|
17
|
+
${hasWrite ? `
|
|
18
|
+
## Write Commands
|
|
15
19
|
|
|
16
20
|
\`\`\`
|
|
17
|
-
kontexted skill create-folder --alias
|
|
18
|
-
kontexted skill create-note --alias
|
|
19
|
-
kontexted skill update-note-content --alias
|
|
21
|
+
kontexted skill create-folder --alias ${a} --name <name> --display-name "<displayName>" [--parent-id <id>]
|
|
22
|
+
kontexted skill create-note --alias ${a} --name <name> --title "<title>" [--folder-id <id>] [--content "<content>"]
|
|
23
|
+
kontexted skill update-note-content --alias ${a} --note-id <id> --content "<content>"
|
|
20
24
|
\`\`\`
|
|
21
|
-
|
|
25
|
+
` : ''}
|
|
22
26
|
## Prerequisites
|
|
23
27
|
|
|
24
28
|
Before using the kontexted CLI skill commands, ensure:
|
|
@@ -26,9 +30,9 @@ Before using the kontexted CLI skill commands, ensure:
|
|
|
26
30
|
1. **kontexted CLI is installed** - Install via npm or your preferred package manager
|
|
27
31
|
2. **User has authenticated** - User must have run \`kontexted login\` with a profile alias
|
|
28
32
|
3. **Profile has a workspace configured** - The profile alias must be associated with an active workspace
|
|
29
|
-
4. **Write operations
|
|
33
|
+
${hasWrite ? `4. **Write operations enabled** - This profile has write access enabled` : ''}
|
|
30
34
|
|
|
31
|
-
All commands require the \`--alias\` parameter
|
|
35
|
+
All commands require the \`--alias\` parameter. ${alias ? `This skill is configured for the \`${alias}\` profile.` : 'The profile must already be set up and authenticated.'}
|
|
32
36
|
|
|
33
37
|
## Available Tools
|
|
34
38
|
|
|
@@ -39,7 +43,7 @@ All commands require the \`--alias\` parameter to specify which profile to use.
|
|
|
39
43
|
Get the complete folder and note structure of a workspace.
|
|
40
44
|
|
|
41
45
|
\`\`\`bash
|
|
42
|
-
kontexted skill workspace-tree --alias
|
|
46
|
+
kontexted skill workspace-tree --alias ${a}
|
|
43
47
|
\`\`\`
|
|
44
48
|
|
|
45
49
|
**Options:**
|
|
@@ -57,7 +61,7 @@ kontexted skill workspace-tree --alias <profile>
|
|
|
57
61
|
Search for notes containing specific text content.
|
|
58
62
|
|
|
59
63
|
\`\`\`bash
|
|
60
|
-
kontexted skill search-notes --alias
|
|
64
|
+
kontexted skill search-notes --alias ${a} --query "<text>" [--limit <n>]
|
|
61
65
|
\`\`\`
|
|
62
66
|
|
|
63
67
|
**Options:**
|
|
@@ -77,7 +81,7 @@ kontexted skill search-notes --alias <profile> --query "<text>" [--limit <n>]
|
|
|
77
81
|
Retrieve the complete content of a specific note by its ID.
|
|
78
82
|
|
|
79
83
|
\`\`\`bash
|
|
80
|
-
kontexted skill note-by-id --alias
|
|
84
|
+
kontexted skill note-by-id --alias ${a} --note-id <id>
|
|
81
85
|
\`\`\`
|
|
82
86
|
|
|
83
87
|
**Options:**
|
|
@@ -90,7 +94,7 @@ kontexted skill note-by-id --alias <profile> --note-id <id>
|
|
|
90
94
|
- When you have a specific note ID and need its content
|
|
91
95
|
- After finding a note via search or workspace tree exploration
|
|
92
96
|
- When the user asks to read a specific note
|
|
93
|
-
|
|
97
|
+
${hasWrite ? `
|
|
94
98
|
### Write Tools
|
|
95
99
|
|
|
96
100
|
#### create-folder
|
|
@@ -98,7 +102,7 @@ kontexted skill note-by-id --alias <profile> --note-id <id>
|
|
|
98
102
|
Create a new folder in the workspace. Optionally nest under a parent folder.
|
|
99
103
|
|
|
100
104
|
\`\`\`bash
|
|
101
|
-
kontexted skill create-folder --alias
|
|
105
|
+
kontexted skill create-folder --alias ${a} --name <name> --display-name "<displayName>" [--parent-id <parentPublicId>]
|
|
102
106
|
\`\`\`
|
|
103
107
|
|
|
104
108
|
**Options:**
|
|
@@ -123,7 +127,7 @@ kontexted skill create-folder --alias <profile> --name <name> --display-name "<d
|
|
|
123
127
|
Create a new note in the workspace. Optionally place in a folder.
|
|
124
128
|
|
|
125
129
|
\`\`\`bash
|
|
126
|
-
kontexted skill create-note --alias
|
|
130
|
+
kontexted skill create-note --alias ${a} --name <name> --title "<title>" [--folder-id <folderPublicId>] [--content "<content>"]
|
|
127
131
|
\`\`\`
|
|
128
132
|
|
|
129
133
|
**Options:**
|
|
@@ -149,7 +153,7 @@ kontexted skill create-note --alias <profile> --name <name> --title "<title>" [-
|
|
|
149
153
|
Update the content of an existing note. This creates a revision for history.
|
|
150
154
|
|
|
151
155
|
\`\`\`bash
|
|
152
|
-
kontexted skill update-note-content --alias
|
|
156
|
+
kontexted skill update-note-content --alias ${a} --note-id <notePublicId> --content "<content>"
|
|
153
157
|
\`\`\`
|
|
154
158
|
|
|
155
159
|
**Options:**
|
|
@@ -172,7 +176,7 @@ kontexted skill update-note-content --alias <profile> --note-id <notePublicId> -
|
|
|
172
176
|
**Error cases:**
|
|
173
177
|
- **"Note not found"** - Verify the note ID
|
|
174
178
|
- **"Invalid note public ID"** - Check the ID format
|
|
175
|
-
|
|
179
|
+
` : ''}
|
|
176
180
|
## Typical Workflow
|
|
177
181
|
|
|
178
182
|
The skill commands work best when combined in a logical sequence:
|
|
@@ -182,7 +186,7 @@ The skill commands work best when combined in a logical sequence:
|
|
|
182
186
|
1. **Explore** - Use \`workspace-tree\` to understand workspace structure
|
|
183
187
|
2. **Search** - Use \`search-notes\` to find relevant notes by content
|
|
184
188
|
3. **Read** - Use \`note-by-id\` to retrieve full content of specific notes
|
|
185
|
-
|
|
189
|
+
${hasWrite ? `
|
|
186
190
|
### Write Workflow
|
|
187
191
|
|
|
188
192
|
1. **Create structure** - Use \`create-folder\` to organize content
|
|
@@ -192,91 +196,76 @@ The skill commands work best when combined in a logical sequence:
|
|
|
192
196
|
**Example write workflow:**
|
|
193
197
|
\`\`\`bash
|
|
194
198
|
# Create a folder for project documentation
|
|
195
|
-
kontexted skill create-folder --alias
|
|
199
|
+
kontexted skill create-folder --alias ${a} --name "project-docs" --display-name "Project Documentation"
|
|
196
200
|
|
|
197
201
|
# Create a note in that folder (use the returned publicId)
|
|
198
|
-
kontexted skill create-note --alias
|
|
202
|
+
kontexted skill create-note --alias ${a} --name "requirements" --title "Requirements" --folder-id "FOLDER_PUBLIC_ID"
|
|
199
203
|
|
|
200
204
|
# Update the note content
|
|
201
|
-
kontexted skill update-note-content --alias
|
|
205
|
+
kontexted skill update-note-content --alias ${a} --note-id "NOTE_PUBLIC_ID" --content "# Requirements\n\n- Feature A\n- Feature B"
|
|
202
206
|
\`\`\`
|
|
203
|
-
|
|
207
|
+
` : ''}
|
|
204
208
|
## Example Usage
|
|
205
209
|
|
|
206
210
|
### Exploring a workspace
|
|
207
211
|
|
|
208
212
|
\`\`\`bash
|
|
209
|
-
|
|
210
|
-
kontexted skill workspace-tree --alias personal
|
|
213
|
+
kontexted skill workspace-tree --alias ${a}
|
|
211
214
|
\`\`\`
|
|
212
215
|
|
|
213
216
|
### Searching for content
|
|
214
217
|
|
|
215
218
|
\`\`\`bash
|
|
216
|
-
|
|
217
|
-
kontexted skill search-notes --alias
|
|
218
|
-
|
|
219
|
-
# Limit results to 3 notes
|
|
220
|
-
kontexted skill search-notes --alias work --query "todo" --limit 3
|
|
219
|
+
kontexted skill search-notes --alias ${a} --query "meeting notes"
|
|
220
|
+
kontexted skill search-notes --alias ${a} --query "todo" --limit 3
|
|
221
221
|
\`\`\`
|
|
222
222
|
|
|
223
223
|
### Reading specific notes
|
|
224
224
|
|
|
225
225
|
\`\`\`bash
|
|
226
|
-
|
|
227
|
-
kontexted skill note-by-id --alias work --note-id "note-uuid-123"
|
|
226
|
+
kontexted skill note-by-id --alias ${a} --note-id "note-uuid-123"
|
|
228
227
|
\`\`\`
|
|
229
|
-
|
|
228
|
+
${hasWrite ? `
|
|
230
229
|
### Creating a folder structure
|
|
231
230
|
|
|
232
231
|
\`\`\`bash
|
|
233
|
-
|
|
234
|
-
kontexted skill create-folder --alias
|
|
235
|
-
|
|
236
|
-
# Create a nested folder (use the returned publicId as parent-id)
|
|
237
|
-
kontexted skill create-folder --alias work --name "2024" --display-name "2024 Meetings" --parent-id "PARENT_FOLDER_ID"
|
|
232
|
+
kontexted skill create-folder --alias ${a} --name "meetings" --display-name "Meeting Notes"
|
|
233
|
+
kontexted skill create-folder --alias ${a} --name "2024" --display-name "2024 Meetings" --parent-id "PARENT_FOLDER_ID"
|
|
238
234
|
\`\`\`
|
|
239
235
|
|
|
240
236
|
### Creating and populating a note
|
|
241
237
|
|
|
242
238
|
\`\`\`bash
|
|
243
|
-
|
|
244
|
-
kontexted skill
|
|
245
|
-
|
|
246
|
-
# Later, update the note content
|
|
247
|
-
kontexted skill update-note-content --alias work --note-id "NOTE_ID" --content "# Todo\n\n- [x] Task 1\n- [ ] Task 2\n- [ ] Task 3"
|
|
239
|
+
kontexted skill create-note --alias ${a} --name "todo" --title "Todo List" --content "# Todo\n\n- [ ] Task 1\n- [ ] Task 2"
|
|
240
|
+
kontexted skill update-note-content --alias ${a} --note-id "NOTE_ID" --content "# Todo\n\n- [x] Task 1\n- [ ] Task 2\n- [ ] Task 3"
|
|
248
241
|
\`\`\`
|
|
249
242
|
|
|
250
243
|
### Combining read and write operations
|
|
251
244
|
|
|
252
245
|
\`\`\`bash
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
kontexted skill search-notes --alias work --query "meeting notes"
|
|
256
|
-
|
|
257
|
-
# Step 2: Update the found note
|
|
258
|
-
kontexted skill update-note-content --alias work --note-id "FOUND_NOTE_ID" --content "Updated content here"
|
|
246
|
+
kontexted skill search-notes --alias ${a} --query "meeting notes"
|
|
247
|
+
kontexted skill update-note-content --alias ${a} --note-id "FOUND_NOTE_ID" --content "Updated content here"
|
|
259
248
|
\`\`\`
|
|
260
|
-
|
|
249
|
+
` : ''}
|
|
261
250
|
## Error Handling
|
|
262
251
|
|
|
263
252
|
### Authentication errors
|
|
264
253
|
|
|
265
|
-
If you encounter authentication errors:
|
|
266
|
-
|
|
267
254
|
1. **"Profile not found"** - The specified alias doesn't exist. Ask the user to run \`kontexted login --alias <profile>\` first.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
3. **"No workspace configured"** - The profile is authenticated but has no workspace. Ask the user to set up a workspace with \`kontexted workspace set --alias <profile>\`.
|
|
272
|
-
|
|
255
|
+
2. **"Not authenticated"** - The profile exists but isn't authenticated. Ask the user to re-authenticate.
|
|
256
|
+
3. **"No workspace configured"** - The profile is authenticated but has no workspace. Ask the user to set up a workspace.
|
|
257
|
+
${hasWrite ? `
|
|
273
258
|
### Write operation errors
|
|
274
259
|
|
|
275
|
-
1. **"Write operations not enabled for this profile"** - Re-login with \`kontexted login --alias
|
|
260
|
+
1. **"Write operations not enabled for this profile"** - Re-login with \`kontexted login --alias ${a} --write\` to enable write access
|
|
276
261
|
2. **"Folder with this name already exists"** - Use a unique name or check existing folders
|
|
277
262
|
3. **"Note with this name already exists"** - Use a unique name or check existing notes
|
|
278
263
|
4. **"Parent folder not found"** - Verify the parent folder ID exists
|
|
279
264
|
5. **"Note not found"** - Verify the note ID is correct
|
|
265
|
+
` : `
|
|
266
|
+
### Write operation errors
|
|
267
|
+
|
|
268
|
+
Write commands are not available for this profile. To enable write access, run \`kontexted login --alias <profile> --write\` and regenerate the skill.`}
|
|
280
269
|
|
|
281
270
|
### Other errors
|
|
282
271
|
|
|
@@ -284,8 +273,6 @@ If you encounter authentication errors:
|
|
|
284
273
|
- **"Workspace not accessible"** - The workspace exists but the user lacks access permissions
|
|
285
274
|
- **"Connection error"** - Network issues. Retry the command or check the user's connection
|
|
286
275
|
|
|
287
|
-
When errors occur, report them clearly to the user so they can take appropriate action. The kontexted CLI handles most errors with descriptive messages.
|
|
288
|
-
|
|
289
276
|
## Output Format
|
|
290
277
|
|
|
291
278
|
All commands return JSON output that is easy to parse:
|
|
@@ -294,12 +281,16 @@ All commands return JSON output that is easy to parse:
|
|
|
294
281
|
- \`workspace-tree\`: Returns nested object with folders and notes
|
|
295
282
|
- \`search-notes\`: Returns array of matching notes with ID, title, and snippets
|
|
296
283
|
- \`note-by-id\`: Returns complete note object with body and metadata
|
|
297
|
-
|
|
284
|
+
${hasWrite ? `
|
|
298
285
|
### Write commands
|
|
299
286
|
- \`create-folder\`: Returns \`{ folder: { publicId, name, displayName, parentPublicId } }\`
|
|
300
287
|
- \`create-note\`: Returns \`{ note: { publicId, name, title, folderPublicId, content } }\`
|
|
301
288
|
- \`update-note-content\`: Returns \`{ note: { publicId, revisionId, updatedAt } }\`
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
289
|
+
` : ''}
|
|
290
|
+
`;
|
|
291
|
+
}
|
|
292
|
+
export const kontextedCliSkill = {
|
|
293
|
+
name: 'kontexted-cli',
|
|
294
|
+
description: 'Access and manage Kontexted workspaces, search notes, retrieve content, and create/update notes and folders through the kontexted CLI. Use when the user needs to explore workspace structure, find specific notes, read note content, or modify workspace content using profile aliases.',
|
|
295
|
+
content: generateKontextedCliContent,
|
|
305
296
|
};
|
|
@@ -9,6 +9,10 @@ export interface InitSkillOptions {
|
|
|
9
9
|
provider: SkillProvider;
|
|
10
10
|
/** Base directory (defaults to current working directory) */
|
|
11
11
|
basePath?: string;
|
|
12
|
+
/** Profile alias to embed in skill content */
|
|
13
|
+
alias?: string;
|
|
14
|
+
/** Whether the profile has write permissions */
|
|
15
|
+
hasWrite?: boolean;
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
18
|
* Result of initializing a skill
|
package/dist/skill-init/utils.js
CHANGED
|
@@ -81,9 +81,11 @@ export function validateSkill(skill, provider) {
|
|
|
81
81
|
else if (skill.description.length < 1 || skill.description.length > 1024) {
|
|
82
82
|
errors.push(`Skill description must be between 1 and 1024 characters (currently ${skill.description.length})`);
|
|
83
83
|
}
|
|
84
|
-
// Validate content is not empty
|
|
85
|
-
if (
|
|
86
|
-
|
|
84
|
+
// Validate content is not empty (skip for generator functions)
|
|
85
|
+
if (typeof skill.content === 'string') {
|
|
86
|
+
if (!skill.content || skill.content.trim().length === 0) {
|
|
87
|
+
errors.push('Skill content is required and cannot be empty');
|
|
88
|
+
}
|
|
87
89
|
}
|
|
88
90
|
return errors;
|
|
89
91
|
}
|
|
@@ -96,13 +98,21 @@ export function validateSkill(skill, provider) {
|
|
|
96
98
|
* @throws Error if validation fails or if the skill cannot be written
|
|
97
99
|
*/
|
|
98
100
|
export async function initSkill(options) {
|
|
99
|
-
const { skill, provider } = options;
|
|
101
|
+
const { skill, provider, alias, hasWrite = false } = options;
|
|
100
102
|
const basePath = options.basePath || process.cwd();
|
|
101
103
|
// Validate the skill definition
|
|
102
104
|
const validationErrors = validateSkill(skill, provider);
|
|
103
105
|
if (validationErrors.length > 0) {
|
|
104
106
|
throw new Error(`Skill validation failed:\n${validationErrors.join('\n')}`);
|
|
105
107
|
}
|
|
108
|
+
// Resolve content - handle both static string and generator function
|
|
109
|
+
let resolvedContent;
|
|
110
|
+
if (typeof skill.content === 'function') {
|
|
111
|
+
resolvedContent = skill.content({ alias, hasWrite });
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
resolvedContent = skill.content;
|
|
115
|
+
}
|
|
106
116
|
// Get the skill path from the provider
|
|
107
117
|
const relativeSkillPath = provider.getSkillPath(skill.name);
|
|
108
118
|
const absoluteSkillPath = path.isAbsolute(relativeSkillPath)
|
|
@@ -110,8 +120,8 @@ export async function initSkill(options) {
|
|
|
110
120
|
: path.resolve(basePath, relativeSkillPath);
|
|
111
121
|
// Check if file already exists
|
|
112
122
|
const alreadyExists = await fileExists(absoluteSkillPath);
|
|
113
|
-
// Generate the skill content
|
|
114
|
-
const skillContent = provider.generateSkillContent(skill);
|
|
123
|
+
// Generate the skill content with resolved content and metadata
|
|
124
|
+
const skillContent = provider.generateSkillContent(skill, resolvedContent, { alias });
|
|
115
125
|
// Write the skill file
|
|
116
126
|
await writeFile(absoluteSkillPath, skillContent);
|
|
117
127
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kontexted",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "CLI tool for Kontexted - MCP proxy, workspaces management, and local server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"typescript": "^5.6.0"
|
|
44
44
|
},
|
|
45
45
|
"optionalDependencies": {
|
|
46
|
-
"@kontexted/darwin-arm64": "0.1.
|
|
47
|
-
"@kontexted/linux-x64": "0.1.
|
|
48
|
-
"@kontexted/windows-x64": "0.1.
|
|
46
|
+
"@kontexted/darwin-arm64": "0.1.11",
|
|
47
|
+
"@kontexted/linux-x64": "0.1.11",
|
|
48
|
+
"@kontexted/windows-x64": "0.1.11"
|
|
49
49
|
}
|
|
50
50
|
}
|