@code-yeongyu/senpi-tui 2026.9.10 → 2026.9.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.
@@ -4,6 +4,6 @@ export interface DollarInvocationContext {
4
4
  readonly query: string;
5
5
  readonly skillsOnly: boolean;
6
6
  }
7
- export declare function getDollarInvocationContext(textBeforeCursor: string, cursorLine: number, commands: readonly (SlashCommand | AutocompleteItem)[]): DollarInvocationContext | null;
7
+ export declare function getDollarInvocationContext(textBeforeCursor: string, _cursorLine: number, commands: readonly (SlashCommand | AutocompleteItem)[]): DollarInvocationContext | null;
8
8
  export declare function getDollarInvocationSuggestions(commands: readonly (SlashCommand | AutocompleteItem)[], query: string, skillsOnly: boolean): AutocompleteItem[];
9
9
  //# sourceMappingURL=dollar-invocation-autocomplete.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dollar-invocation-autocomplete.d.ts","sourceRoot":"","sources":["../src/dollar-invocation-autocomplete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAcxE,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC7B;AAmBD,wBAAgB,0BAA0B,CACzC,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,SAAS,CAAC,YAAY,GAAG,gBAAgB,CAAC,EAAE,GACpD,uBAAuB,GAAG,IAAI,CA0BhC;AAED,wBAAgB,8BAA8B,CAC7C,QAAQ,EAAE,SAAS,CAAC,YAAY,GAAG,gBAAgB,CAAC,EAAE,EACtD,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,OAAO,GACjB,gBAAgB,EAAE,CAkCpB"}
1
+ {"version":3,"file":"dollar-invocation-autocomplete.d.ts","sourceRoot":"","sources":["../src/dollar-invocation-autocomplete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA+BxE,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC7B;AAwCD,wBAAgB,0BAA0B,CACzC,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,SAAS,CAAC,YAAY,GAAG,gBAAgB,CAAC,EAAE,GACpD,uBAAuB,GAAG,IAAI,CA0BhC;AAED,wBAAgB,8BAA8B,CAC7C,QAAQ,EAAE,SAAS,CAAC,YAAY,GAAG,gBAAgB,CAAC,EAAE,EACtD,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,OAAO,GACjB,gBAAgB,EAAE,CAkCpB"}
@@ -1,6 +1,43 @@
1
1
  import { fuzzyFilter } from "./fuzzy.js";
2
2
  const SKILL_COMMAND_PREFIX = "skill:";
3
- const LEADING_DOLLAR_RUN_PATTERN = /^((?:\$[a-zA-Z][a-zA-Z0-9:_-]*\s+)*)\$([a-zA-Z0-9:_-]*)$/;
3
+ const DOLLAR_QUERY_PATTERN = /^\$([a-zA-Z0-9:_-]*)$/;
4
+ const COMMON_SHELL_VARIABLES = new Set([
5
+ "CI",
6
+ "EDITOR",
7
+ "HOME",
8
+ "LANG",
9
+ "LC_ALL",
10
+ "NODE_ENV",
11
+ "OLDPWD",
12
+ "PATH",
13
+ "PWD",
14
+ "SHELL",
15
+ "SHLVL",
16
+ "TERM",
17
+ "TMPDIR",
18
+ "USER",
19
+ "VISUAL",
20
+ ]);
21
+ function isDollarQueryCompletable(query) {
22
+ if (query === "")
23
+ return true;
24
+ if (query.startsWith("-") || query.startsWith("_") || /^\d/.test(query))
25
+ return false;
26
+ return !COMMON_SHELL_VARIABLES.has(query);
27
+ }
28
+ function leadingKnownSkillRun(text, knownSkills) {
29
+ const tokens = text.trim().split(/\s+/).filter(Boolean);
30
+ return (tokens.length > 0 &&
31
+ tokens.every((token) => {
32
+ const match = DOLLAR_QUERY_PATTERN.exec(token);
33
+ if (match === null || match[1] === "")
34
+ return false;
35
+ const name = match[1].startsWith(SKILL_COMMAND_PREFIX)
36
+ ? match[1].slice(SKILL_COMMAND_PREFIX.length)
37
+ : match[1];
38
+ return name !== "" && knownSkills.has(name);
39
+ }));
40
+ }
4
41
  function commandName(command) {
5
42
  return "name" in command ? command.name : command.value;
6
43
  }
@@ -17,30 +54,32 @@ function commandDescription(command) {
17
54
  return description ? `${hint} — ${description}` : hint;
18
55
  return description || undefined;
19
56
  }
20
- export function getDollarInvocationContext(textBeforeCursor, cursorLine, commands) {
21
- if (cursorLine !== 0)
22
- return null;
23
- const match = textBeforeCursor.match(LEADING_DOLLAR_RUN_PATTERN);
24
- if (!match)
25
- return null;
57
+ export function getDollarInvocationContext(textBeforeCursor, _cursorLine, commands) {
26
58
  const knownSkills = new Set(commands.flatMap((command) => {
27
59
  const name = skillName(commandName(command));
28
60
  return name ? [name] : [];
29
61
  }));
30
- const precedingSkills = match[1]
31
- .trim()
32
- .split(/\s+/)
33
- .filter(Boolean)
34
- .map((token) => token.slice(1))
35
- .map((name) => (name.startsWith(SKILL_COMMAND_PREFIX) ? name.slice(SKILL_COMMAND_PREFIX.length) : name));
36
- if (precedingSkills.some((name) => !knownSkills.has(name)))
62
+ const tokenStart = textBeforeCursor.search(/\S+$/);
63
+ const token = tokenStart === -1 ? "" : textBeforeCursor.slice(tokenStart);
64
+ const match = DOLLAR_QUERY_PATTERN.exec(token);
65
+ if (!match)
66
+ return null;
67
+ const rawQuery = match[1];
68
+ if (!isDollarQueryCompletable(rawQuery))
37
69
  return null;
38
- const rawQuery = match[2];
39
70
  const explicitSkillNamespace = rawQuery.startsWith(SKILL_COMMAND_PREFIX);
71
+ const precedingText = tokenStart === -1 ? "" : textBeforeCursor.slice(0, tokenStart);
72
+ const hasEarlierDollarToken = precedingText.includes("$");
73
+ const hasKnownLeadingSkillRun = leadingKnownSkillRun(precedingText, knownSkills);
74
+ if (hasEarlierDollarToken && !hasKnownLeadingSkillRun)
75
+ return null;
76
+ const isKnownSkillInOrdinaryText = !hasKnownLeadingSkillRun && knownSkills.has(rawQuery);
77
+ if (isKnownSkillInOrdinaryText)
78
+ return null;
40
79
  return {
41
80
  prefix: `$${rawQuery}`,
42
81
  query: explicitSkillNamespace ? rawQuery.slice(SKILL_COMMAND_PREFIX.length) : rawQuery,
43
- skillsOnly: precedingSkills.length > 0 || explicitSkillNamespace,
82
+ skillsOnly: hasKnownLeadingSkillRun || explicitSkillNamespace,
44
83
  };
45
84
  }
46
85
  export function getDollarInvocationSuggestions(commands, query, skillsOnly) {
@@ -1 +1 @@
1
- {"version":3,"file":"dollar-invocation-autocomplete.js","sourceRoot":"","sources":["../src/dollar-invocation-autocomplete.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AutocompleteItem, SlashCommand } from \"./autocomplete.ts\";\nimport { fuzzyFilter } from \"./fuzzy.ts\";\n\nconst SKILL_COMMAND_PREFIX = \"skill:\";\nconst LEADING_DOLLAR_RUN_PATTERN = /^((?:\\$[a-zA-Z][a-zA-Z0-9:_-]*\\s+)*)\\$([a-zA-Z0-9:_-]*)$/;\n\ntype DollarInvocationItem = {\n\treadonly description?: string;\n\treadonly kind: \"command\" | \"skill\";\n\treadonly label: string;\n\treadonly searchText: string;\n\treadonly value: string;\n};\n\nexport interface DollarInvocationContext {\n\treadonly prefix: string;\n\treadonly query: string;\n\treadonly skillsOnly: boolean;\n}\n\nfunction commandName(command: SlashCommand | AutocompleteItem): string {\n\treturn \"name\" in command ? command.name : command.value;\n}\n\nfunction skillName(name: string): string | null {\n\tif (!name.startsWith(SKILL_COMMAND_PREFIX)) return null;\n\tconst value = name.slice(SKILL_COMMAND_PREFIX.length);\n\treturn value || null;\n}\n\nfunction commandDescription(command: SlashCommand | AutocompleteItem): string | undefined {\n\tconst hint = \"argumentHint\" in command && command.argumentHint ? command.argumentHint : undefined;\n\tconst description = command.description ?? \"\";\n\tif (hint) return description ? `${hint} — ${description}` : hint;\n\treturn description || undefined;\n}\n\nexport function getDollarInvocationContext(\n\ttextBeforeCursor: string,\n\tcursorLine: number,\n\tcommands: readonly (SlashCommand | AutocompleteItem)[],\n): DollarInvocationContext | null {\n\tif (cursorLine !== 0) return null;\n\tconst match = textBeforeCursor.match(LEADING_DOLLAR_RUN_PATTERN);\n\tif (!match) return null;\n\n\tconst knownSkills = new Set(\n\t\tcommands.flatMap((command) => {\n\t\t\tconst name = skillName(commandName(command));\n\t\t\treturn name ? [name] : [];\n\t\t}),\n\t);\n\tconst precedingSkills = match[1]\n\t\t.trim()\n\t\t.split(/\\s+/)\n\t\t.filter(Boolean)\n\t\t.map((token) => token.slice(1))\n\t\t.map((name) => (name.startsWith(SKILL_COMMAND_PREFIX) ? name.slice(SKILL_COMMAND_PREFIX.length) : name));\n\tif (precedingSkills.some((name) => !knownSkills.has(name))) return null;\n\n\tconst rawQuery = match[2];\n\tconst explicitSkillNamespace = rawQuery.startsWith(SKILL_COMMAND_PREFIX);\n\treturn {\n\t\tprefix: `$${rawQuery}`,\n\t\tquery: explicitSkillNamespace ? rawQuery.slice(SKILL_COMMAND_PREFIX.length) : rawQuery,\n\t\tskillsOnly: precedingSkills.length > 0 || explicitSkillNamespace,\n\t};\n}\n\nexport function getDollarInvocationSuggestions(\n\tcommands: readonly (SlashCommand | AutocompleteItem)[],\n\tquery: string,\n\tskillsOnly: boolean,\n): AutocompleteItem[] {\n\tconst items: DollarInvocationItem[] = commands.flatMap((command): DollarInvocationItem[] => {\n\t\tconst name = commandName(command);\n\t\tconst skill = skillName(name);\n\t\tif (skill) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkind: \"skill\" as const,\n\t\t\t\t\tvalue: `$${skill}`,\n\t\t\t\t\tlabel: `$${skill}`,\n\t\t\t\t\tsearchText: skill,\n\t\t\t\t\tdescription: commandDescription(command),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\tif (skillsOnly) return [];\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: \"command\" as const,\n\t\t\t\tvalue: `/${name}`,\n\t\t\t\tlabel: `/${name}`,\n\t\t\t\tsearchText: name,\n\t\t\t\tdescription: commandDescription(command),\n\t\t\t},\n\t\t];\n\t});\n\n\treturn fuzzyFilter(items, query, (item) => item.searchText)\n\t\t.map((item, index) => ({ ...item, index }))\n\t\t.sort((left, right) => {\n\t\t\tif (left.kind !== right.kind) return left.kind === \"command\" ? -1 : 1;\n\t\t\treturn left.index - right.index;\n\t\t})\n\t\t.map(({ index: _index, kind: _kind, searchText: _searchText, ...item }) => item);\n}\n"]}
1
+ {"version":3,"file":"dollar-invocation-autocomplete.js","sourceRoot":"","sources":["../src/dollar-invocation-autocomplete.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AutocompleteItem, SlashCommand } from \"./autocomplete.ts\";\nimport { fuzzyFilter } from \"./fuzzy.ts\";\n\nconst SKILL_COMMAND_PREFIX = \"skill:\";\nconst DOLLAR_QUERY_PATTERN = /^\\$([a-zA-Z0-9:_-]*)$/;\nconst COMMON_SHELL_VARIABLES = new Set([\n\t\"CI\",\n\t\"EDITOR\",\n\t\"HOME\",\n\t\"LANG\",\n\t\"LC_ALL\",\n\t\"NODE_ENV\",\n\t\"OLDPWD\",\n\t\"PATH\",\n\t\"PWD\",\n\t\"SHELL\",\n\t\"SHLVL\",\n\t\"TERM\",\n\t\"TMPDIR\",\n\t\"USER\",\n\t\"VISUAL\",\n]);\n\ntype DollarInvocationItem = {\n\treadonly description?: string;\n\treadonly kind: \"command\" | \"skill\";\n\treadonly label: string;\n\treadonly searchText: string;\n\treadonly value: string;\n};\n\nexport interface DollarInvocationContext {\n\treadonly prefix: string;\n\treadonly query: string;\n\treadonly skillsOnly: boolean;\n}\n\nfunction isDollarQueryCompletable(query: string): boolean {\n\tif (query === \"\") return true;\n\tif (query.startsWith(\"-\") || query.startsWith(\"_\") || /^\\d/.test(query)) return false;\n\treturn !COMMON_SHELL_VARIABLES.has(query);\n}\n\nfunction leadingKnownSkillRun(text: string, knownSkills: ReadonlySet<string>): boolean {\n\tconst tokens = text.trim().split(/\\s+/).filter(Boolean);\n\treturn (\n\t\ttokens.length > 0 &&\n\t\ttokens.every((token) => {\n\t\t\tconst match = DOLLAR_QUERY_PATTERN.exec(token);\n\t\t\tif (match === null || match[1] === \"\") return false;\n\t\t\tconst name = match[1].startsWith(SKILL_COMMAND_PREFIX)\n\t\t\t\t? match[1].slice(SKILL_COMMAND_PREFIX.length)\n\t\t\t\t: match[1];\n\t\t\treturn name !== \"\" && knownSkills.has(name);\n\t\t})\n\t);\n}\n\nfunction commandName(command: SlashCommand | AutocompleteItem): string {\n\treturn \"name\" in command ? command.name : command.value;\n}\n\nfunction skillName(name: string): string | null {\n\tif (!name.startsWith(SKILL_COMMAND_PREFIX)) return null;\n\tconst value = name.slice(SKILL_COMMAND_PREFIX.length);\n\treturn value || null;\n}\n\nfunction commandDescription(command: SlashCommand | AutocompleteItem): string | undefined {\n\tconst hint = \"argumentHint\" in command && command.argumentHint ? command.argumentHint : undefined;\n\tconst description = command.description ?? \"\";\n\tif (hint) return description ? `${hint} — ${description}` : hint;\n\treturn description || undefined;\n}\n\nexport function getDollarInvocationContext(\n\ttextBeforeCursor: string,\n\t_cursorLine: number,\n\tcommands: readonly (SlashCommand | AutocompleteItem)[],\n): DollarInvocationContext | null {\n\tconst knownSkills = new Set(\n\t\tcommands.flatMap((command) => {\n\t\t\tconst name = skillName(commandName(command));\n\t\t\treturn name ? [name] : [];\n\t\t}),\n\t);\n\tconst tokenStart = textBeforeCursor.search(/\\S+$/);\n\tconst token = tokenStart === -1 ? \"\" : textBeforeCursor.slice(tokenStart);\n\tconst match = DOLLAR_QUERY_PATTERN.exec(token);\n\tif (!match) return null;\n\n\tconst rawQuery = match[1];\n\tif (!isDollarQueryCompletable(rawQuery)) return null;\n\tconst explicitSkillNamespace = rawQuery.startsWith(SKILL_COMMAND_PREFIX);\n\tconst precedingText = tokenStart === -1 ? \"\" : textBeforeCursor.slice(0, tokenStart);\n\tconst hasEarlierDollarToken = precedingText.includes(\"$\");\n\tconst hasKnownLeadingSkillRun = leadingKnownSkillRun(precedingText, knownSkills);\n\tif (hasEarlierDollarToken && !hasKnownLeadingSkillRun) return null;\n\tconst isKnownSkillInOrdinaryText = !hasKnownLeadingSkillRun && knownSkills.has(rawQuery);\n\tif (isKnownSkillInOrdinaryText) return null;\n\treturn {\n\t\tprefix: `$${rawQuery}`,\n\t\tquery: explicitSkillNamespace ? rawQuery.slice(SKILL_COMMAND_PREFIX.length) : rawQuery,\n\t\tskillsOnly: hasKnownLeadingSkillRun || explicitSkillNamespace,\n\t};\n}\n\nexport function getDollarInvocationSuggestions(\n\tcommands: readonly (SlashCommand | AutocompleteItem)[],\n\tquery: string,\n\tskillsOnly: boolean,\n): AutocompleteItem[] {\n\tconst items: DollarInvocationItem[] = commands.flatMap((command): DollarInvocationItem[] => {\n\t\tconst name = commandName(command);\n\t\tconst skill = skillName(name);\n\t\tif (skill) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkind: \"skill\" as const,\n\t\t\t\t\tvalue: `$${skill}`,\n\t\t\t\t\tlabel: `$${skill}`,\n\t\t\t\t\tsearchText: skill,\n\t\t\t\t\tdescription: commandDescription(command),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\tif (skillsOnly) return [];\n\t\treturn [\n\t\t\t{\n\t\t\t\tkind: \"command\" as const,\n\t\t\t\tvalue: `/${name}`,\n\t\t\t\tlabel: `/${name}`,\n\t\t\t\tsearchText: name,\n\t\t\t\tdescription: commandDescription(command),\n\t\t\t},\n\t\t];\n\t});\n\n\treturn fuzzyFilter(items, query, (item) => item.searchText)\n\t\t.map((item, index) => ({ ...item, index }))\n\t\t.sort((left, right) => {\n\t\t\tif (left.kind !== right.kind) return left.kind === \"command\" ? -1 : 1;\n\t\t\treturn left.index - right.index;\n\t\t})\n\t\t.map(({ index: _index, kind: _kind, searchText: _searchText, ...item }) => item);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-tui",
3
- "version": "2026.9.10",
3
+ "version": "2026.9.11",
4
4
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",