@alisio/alisio-code 0.1.0-alpha.10 → 0.1.0-alpha.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -124,6 +124,77 @@ export declare function parseCommand(input: string): {
124
124
  name: string;
125
125
  args: string;
126
126
  } | undefined;
127
+ /** Minimal structural view of a skill for slash autocompletion (subset of the core catalog entry). */
128
+ export interface SkillCompletionEntry {
129
+ id: string;
130
+ name: string;
131
+ displayId: string;
132
+ description: string;
133
+ /** Catalog scope of the skill: user | project | config | plugin (drives the [u]/[p]/[c]/[l] marker). */
134
+ scope?: string;
135
+ enabled: boolean;
136
+ locked: boolean;
137
+ effective: boolean;
138
+ }
139
+ export interface SlashCompletionItem {
140
+ value: string;
141
+ label: string;
142
+ description?: string;
143
+ }
144
+ export declare const SKILL_COMPLETION_DESCRIPTION_LIMIT = 80;
145
+ /**
146
+ * OpenCode-style scope marker for a skill's slash entry, mirroring the catalog scopes the /skills
147
+ * manager shows: user, project, config and plugin (plugin skills are locked by their owner plugin).
148
+ */
149
+ export declare const skillScopeMarker: (skill: SkillCompletionEntry) => string | undefined;
150
+ /**
151
+ * Description for a skill's first-class `skill:<id>` slash entry: scope marker, status hint, then
152
+ * the skill description truncated to the shared limit. The marker and status are prepended before
153
+ * truncating, so they survive the cap just like the /skills argument completions.
154
+ */
155
+ export declare function skillSlashDescription(skill: SkillCompletionEntry): string;
156
+ /**
157
+ * Suggested completions for `/skills <prefix>`: every entry the /skills manager shows, filtered by
158
+ * prefix (case-insensitive) on name or description. Selecting a suggestion only fills the argument;
159
+ * submitting still opens the skills manager.
160
+ */
161
+ export declare function skillCompletions(catalog: SkillCompletionEntry[], prefix: string, limit?: number): SlashCompletionItem[];
162
+ export interface SlashCompletionSource {
163
+ name: string;
164
+ description?: string;
165
+ argumentHint?: string;
166
+ aliases?: string[];
167
+ }
168
+ export interface SlashCompletionContext {
169
+ /** Live session rows for `/resume`: already filtered to the typed prefix and mapped. */
170
+ sessions?: (prefix: string) => SlashCompletionItem[];
171
+ /** Effective skill catalog backing `/skills` (the same entries the skills manager shows). */
172
+ skills: SkillCompletionEntry[];
173
+ }
174
+ /**
175
+ * Builds the editor slash-autocomplete command list. Aliases get their own entries with the same
176
+ * description and argument completions, because the provider matches commands by fuzzy name.
177
+ * Effective skills are appended as first-class `skill:<id>` entries so `/ski…`, `/skill:b…` and
178
+ * even `/branch…` all surface them; submitting already routes `skill:` commands to skill load, so
179
+ * selecting an entry only needs to insert the command name. `options.skillEntries: false` gates
180
+ * ONLY those standalone `skill:` entries (e.g. the `tui.skillSlashCommands` toggle): the `/skills`
181
+ * manager and its argument completion keep working, since `context.skills` still feeds both.
182
+ */
183
+ export interface SlashCompletionOptions {
184
+ /** Include first-class `skill:<id>` entries for effective skills (default true). */
185
+ skillEntries?: boolean;
186
+ }
187
+ export declare function slashCompletionCommands(sources: SlashCompletionSource[], context: SlashCompletionContext, options?: SlashCompletionOptions): ({
188
+ getArgumentCompletions: (prefix: string) => SlashCompletionItem[];
189
+ name: string;
190
+ description: string | undefined;
191
+ argumentHint?: string | undefined;
192
+ } | {
193
+ getArgumentCompletions?: undefined;
194
+ name: string;
195
+ description: string | undefined;
196
+ argumentHint?: string | undefined;
197
+ })[];
127
198
  export declare function summarizeToolArgs(name: string, args: string): string;
128
199
  export interface DiffLine {
129
200
  sign: "+" | "-";
package/dist/tui/state.js CHANGED
@@ -223,6 +223,11 @@ export const COMMANDS = [
223
223
  aliases: ["skill"],
224
224
  },
225
225
  { name: "mcp", description: "Browse and manage MCP servers" },
226
+ {
227
+ name: "settings",
228
+ description: "Open the settings menu",
229
+ aliases: ["prefs"],
230
+ },
226
231
  { name: "copy", description: "Copy the last assistant response to the clipboard" },
227
232
  {
228
233
  name: "ask",
@@ -245,6 +250,87 @@ export function parseCommand(input) {
245
250
  return undefined;
246
251
  return { name: match[1], args: (match[2] ?? "").trim() };
247
252
  }
253
+ export const SKILL_COMPLETION_DESCRIPTION_LIMIT = 80;
254
+ /** Status hint prefixes (no color): shadowed < disabled < locked states shown by /skills. */
255
+ const skillStatus = (skill) => !skill.effective
256
+ ? "shadowed"
257
+ : !skill.enabled
258
+ ? "disabled"
259
+ : skill.locked
260
+ ? "locked by plugin"
261
+ : undefined;
262
+ /**
263
+ * OpenCode-style scope marker for a skill's slash entry, mirroring the catalog scopes the /skills
264
+ * manager shows: user, project, config and plugin (plugin skills are locked by their owner plugin).
265
+ */
266
+ export const skillScopeMarker = (skill) => {
267
+ const marker = { user: "[u]", project: "[p]", config: "[c]", plugin: "[l]" }[skill.scope];
268
+ return marker ?? (skill.scope ? `[${skill.scope}]` : undefined);
269
+ };
270
+ /**
271
+ * Description for a skill's first-class `skill:<id>` slash entry: scope marker, status hint, then
272
+ * the skill description truncated to the shared limit. The marker and status are prepended before
273
+ * truncating, so they survive the cap just like the /skills argument completions.
274
+ */
275
+ export function skillSlashDescription(skill) {
276
+ const marker = skillScopeMarker(skill);
277
+ const status = skillStatus(skill);
278
+ if (!marker && !status)
279
+ return truncatePlain(skill.description, SKILL_COMPLETION_DESCRIPTION_LIMIT);
280
+ return truncatePlain(`${[marker, status].filter(Boolean).join(" ")}${status ? " · " : " "}${skill.description}`, SKILL_COMPLETION_DESCRIPTION_LIMIT);
281
+ }
282
+ /**
283
+ * Suggested completions for `/skills <prefix>`: every entry the /skills manager shows, filtered by
284
+ * prefix (case-insensitive) on name or description. Selecting a suggestion only fills the argument;
285
+ * submitting still opens the skills manager.
286
+ */
287
+ export function skillCompletions(catalog, prefix, limit = 20) {
288
+ const query = prefix.trim().toLowerCase();
289
+ const items = query
290
+ ? catalog.filter((skill) => [skill.displayId, skill.name, skill.description].join(" ").toLowerCase().includes(query))
291
+ : catalog;
292
+ return items.slice(0, limit).map((skill) => {
293
+ const status = skillStatus(skill);
294
+ return {
295
+ value: skill.id,
296
+ label: skill.displayId,
297
+ description: truncatePlain(status ? `${status} · ${skill.description}` : skill.description, SKILL_COMPLETION_DESCRIPTION_LIMIT),
298
+ };
299
+ });
300
+ }
301
+ function argumentCompletionsFor(source, context) {
302
+ const sessions = context.sessions;
303
+ if (source.name === "resume" && sessions)
304
+ return {
305
+ getArgumentCompletions: (prefix) => sessions(prefix).slice(0, 20),
306
+ };
307
+ if (source.name === "skills")
308
+ return {
309
+ getArgumentCompletions: (prefix) => skillCompletions(context.skills, prefix, 20),
310
+ };
311
+ return {};
312
+ }
313
+ export function slashCompletionCommands(sources, context, options = {}) {
314
+ const entries = sources.flatMap((source) => {
315
+ const entry = (name) => ({
316
+ name,
317
+ description: source.description,
318
+ ...(source.argumentHint ? { argumentHint: source.argumentHint } : {}),
319
+ ...argumentCompletionsFor(source, context),
320
+ });
321
+ return [
322
+ entry(source.name),
323
+ ...(source.aliases ?? []).filter((a) => a !== source.name).map(entry),
324
+ ];
325
+ });
326
+ if (options.skillEntries !== false)
327
+ for (const skill of context.skills)
328
+ entries.push({
329
+ name: `skill:${skill.id}`,
330
+ description: skillSlashDescription(skill),
331
+ });
332
+ return entries;
333
+ }
248
334
  function parseArgs(args) {
249
335
  try {
250
336
  const value = JSON.parse(args);
@@ -505,7 +591,7 @@ export function reduceEvent(state, event) {
505
591
  case "response_truncated":
506
592
  return addItem(state, {
507
593
  kind: "notice",
508
- text: "Response cut by max output tokens — the answer may be incomplete. Raise limits.maxOutputTokens to allow longer answers.",
594
+ text: "Response cut by max output tokens — the answer may be incomplete. Raise limits.maxOutputTokens (/settings → Agent max output tokens) to allow longer answers.",
509
595
  });
510
596
  case "model_changed":
511
597
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alisio/alisio-code",
3
- "version": "0.1.0-alpha.10",
3
+ "version": "0.1.0-alpha.12",
4
4
  "description": "Alisio: an extensible, provider-agnostic coding-agent harness for your terminal. TUI, OpenAI-compatible providers, permissioned local tools, context compaction, persistent memory and a typed plugin SDK.",
5
5
  "author": "Gustavo Gutiérrez",
6
6
  "license": "MIT",
@@ -45,14 +45,14 @@
45
45
  "alisio": "./dist/main.js"
46
46
  },
47
47
  "dependencies": {
48
- "@alisio/core": "0.1.0-alpha.8",
49
- "@alisio/plugin-deepseek": "0.1.0-alpha.7",
48
+ "@alisio/core": "0.1.0-alpha.10",
49
+ "@alisio/plugin-deepseek": "0.1.0-alpha.8",
50
50
  "@alisio/plugin-memory": "0.1.0-alpha.6",
51
- "@alisio/plugin-openai-compatible": "0.1.0-alpha.7",
52
- "@alisio/plugin-opencode": "0.1.0-alpha.6",
53
- "@alisio/plugin-opencode-go": "0.1.0-alpha.6",
54
- "@alisio/plugin-subagents": "0.1.0-alpha.6",
55
- "@alisio/sdk": "0.1.0-alpha.5",
51
+ "@alisio/plugin-openai-compatible": "0.1.0-alpha.8",
52
+ "@alisio/plugin-opencode": "0.1.0-alpha.7",
53
+ "@alisio/plugin-opencode-go": "0.1.0-alpha.7",
54
+ "@alisio/plugin-subagents": "0.1.0-alpha.7",
55
+ "@alisio/sdk": "0.1.0-alpha.6",
56
56
  "@earendil-works/pi-tui": "0.87.1",
57
57
  "commander": "15.0.0"
58
58
  },