jeo-code 0.5.1 → 0.5.2

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/README.ja.md CHANGED
@@ -150,11 +150,11 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
150
150
  ## 変更履歴 (Changelog)
151
151
 
152
152
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
153
+ - **[0.5.2]** (2026-06-14) — `$skill` prompt invocation with prefix/fuzzy suggestions, and a per-session input-box hue (amber in cmd-mode).
153
154
  - **[0.5.1]** (2026-06-14) — cmd-mode `!<command>` shell escape — run a shell command without engaging the agent.
154
155
  - **[0.5.0]** (2026-06-14) — Performance: workspace-scan, workflow-state, and DNA-Claw HUD caches; plus a credential-safety fix that never wipes OAuth over an invalid config.
155
156
  - **[0.4.9]** (2026-06-14) — Live-frame width-clamp (content-sized height) replaces the constant-height approach, typed text shows during a running turn, and a docs/AGENTS refresh.
156
157
  - **[0.4.8]** (2026-06-14) — Live-frame stability: constant-height live turn, renderer self-heal off-by-one fix, and frame-safe child-stdout sanitizing — no more duplicate model bar or torn escapes.
157
- - **[0.4.7]** (2026-06-14) — Detached subagents + `subagent` control tool, live shaded in-flight output, registry-driven providers, fuller `read` budget, styled italics in the final report, and `gjc` retired.
158
158
 
159
159
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
160
160
  <!-- CHANGELOG:END -->
package/README.ko.md CHANGED
@@ -150,11 +150,11 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
150
150
  ## 변경 이력 (Changelog)
151
151
 
152
152
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
153
+ - **[0.5.2]** (2026-06-14) — `$skill` prompt invocation with prefix/fuzzy suggestions, and a per-session input-box hue (amber in cmd-mode).
153
154
  - **[0.5.1]** (2026-06-14) — cmd-mode `!<command>` shell escape — run a shell command without engaging the agent.
154
155
  - **[0.5.0]** (2026-06-14) — Performance: workspace-scan, workflow-state, and DNA-Claw HUD caches; plus a credential-safety fix that never wipes OAuth over an invalid config.
155
156
  - **[0.4.9]** (2026-06-14) — Live-frame width-clamp (content-sized height) replaces the constant-height approach, typed text shows during a running turn, and a docs/AGENTS refresh.
156
157
  - **[0.4.8]** (2026-06-14) — Live-frame stability: constant-height live turn, renderer self-heal off-by-one fix, and frame-safe child-stdout sanitizing — no more duplicate model bar or torn escapes.
157
- - **[0.4.7]** (2026-06-14) — Detached subagents + `subagent` control tool, live shaded in-flight output, registry-driven providers, fuller `read` budget, styled italics in the final report, and `gjc` retired.
158
158
 
159
159
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
160
160
  <!-- CHANGELOG:END -->
package/README.md CHANGED
@@ -150,11 +150,11 @@ Required npm token permissions (repository secret `NPM_TOKEN`):
150
150
  ## Changelog
151
151
 
152
152
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
153
+ - **[0.5.2]** (2026-06-14) — `$skill` prompt invocation with prefix/fuzzy suggestions, and a per-session input-box hue (amber in cmd-mode).
153
154
  - **[0.5.1]** (2026-06-14) — cmd-mode `!<command>` shell escape — run a shell command without engaging the agent.
154
155
  - **[0.5.0]** (2026-06-14) — Performance: workspace-scan, workflow-state, and DNA-Claw HUD caches; plus a credential-safety fix that never wipes OAuth over an invalid config.
155
156
  - **[0.4.9]** (2026-06-14) — Live-frame width-clamp (content-sized height) replaces the constant-height approach, typed text shows during a running turn, and a docs/AGENTS refresh.
156
157
  - **[0.4.8]** (2026-06-14) — Live-frame stability: constant-height live turn, renderer self-heal off-by-one fix, and frame-safe child-stdout sanitizing — no more duplicate model bar or torn escapes.
157
- - **[0.4.7]** (2026-06-14) — Detached subagents + `subagent` control tool, live shaded in-flight output, registry-driven providers, fuller `read` budget, styled italics in the final report, and `gjc` retired.
158
158
 
159
159
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
160
160
  <!-- CHANGELOG:END -->
package/README.zh.md CHANGED
@@ -150,11 +150,11 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
150
150
  ## 更新日志 (Changelog)
151
151
 
152
152
  <!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
153
+ - **[0.5.2]** (2026-06-14) — `$skill` prompt invocation with prefix/fuzzy suggestions, and a per-session input-box hue (amber in cmd-mode).
153
154
  - **[0.5.1]** (2026-06-14) — cmd-mode `!<command>` shell escape — run a shell command without engaging the agent.
154
155
  - **[0.5.0]** (2026-06-14) — Performance: workspace-scan, workflow-state, and DNA-Claw HUD caches; plus a credential-safety fix that never wipes OAuth over an invalid config.
155
156
  - **[0.4.9]** (2026-06-14) — Live-frame width-clamp (content-sized height) replaces the constant-height approach, typed text shows during a running turn, and a docs/AGENTS refresh.
156
157
  - **[0.4.8]** (2026-06-14) — Live-frame stability: constant-height live turn, renderer self-heal off-by-one fix, and frame-safe child-stdout sanitizing — no more duplicate model bar or torn escapes.
157
- - **[0.4.7]** (2026-06-14) — Detached subagents + `subagent` control tool, live shaded in-flight output, registry-driven providers, fuller `read` budget, styled italics in the final report, and `gjc` retired.
158
158
 
159
159
  See [CHANGELOG.md](CHANGELOG.md) for the full history.
160
160
  <!-- CHANGELOG:END -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jeo-code",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Clean, highly optimized AI coding agent using spec-first loop",
5
5
  "type": "module",
6
6
  "main": "src/cli.ts",
@@ -2148,6 +2148,27 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
2148
2148
  let uiTheme = resolveTheme(process.env);
2149
2149
  let uiAccent = accentPaint(uiTheme);
2150
2150
  let uiAccentShadow = accentShadowPaint(uiTheme);
2151
+ // Input-box border colors. Each opened session gets a DISTINCT hue (so several jeo
2152
+ // sessions are tellable apart at a glance), and cmd-mode (`!`) overrides it with a
2153
+ // caution amber so entering the shell escape is unmistakable.
2154
+ const SESSION_BOX_ACCENTS = ["#48dbfb", "#39ff14", "#a29bfe", "#1dd1a1", "#ff9ff3", "#54a0ff", "#ff6b81", "#c8d6e5"];
2155
+ const CMD_MODE_BOX_ACCENT = "#ffb300";
2156
+ const hexPaint = (hex: string) => (s: string) => chalk.hex(hex)(s);
2157
+ const hexShadowPaint = (hex: string) => (s: string) => chalk.dim(chalk.hex(hex)(s));
2158
+ // Per-process random start so different jeo processes differ at a glance; advanced on
2159
+ // each newly opened session (advanceSessionBoxColor) so consecutive sessions never match.
2160
+ let sessionBoxColorIdx = Math.floor(Math.random() * SESSION_BOX_ACCENTS.length);
2161
+ const advanceSessionBoxColor = (): void => {
2162
+ sessionBoxColorIdx = (sessionBoxColorIdx + 1) % SESSION_BOX_ACCENTS.length;
2163
+ };
2164
+ // Resolve the box painters for the current draft: cmd-mode amber when it starts with
2165
+ // `!`, else the per-session hue, else the theme accent (colorless theme / no session).
2166
+ const boxAccents = (line: string): { accent: (s: string) => string; shadow: (s: string) => string } => {
2167
+ if (!uiTheme.color) return { accent: uiAccent, shadow: uiAccentShadow };
2168
+ if (line.startsWith("!")) return { accent: hexPaint(CMD_MODE_BOX_ACCENT), shadow: hexShadowPaint(CMD_MODE_BOX_ACCENT) };
2169
+ if (sessionId) { const hex = SESSION_BOX_ACCENTS[sessionBoxColorIdx]!; return { accent: hexPaint(hex), shadow: hexShadowPaint(hex) }; }
2170
+ return { accent: uiAccent, shadow: uiAccentShadow };
2171
+ };
2151
2172
  const refreshUiTheme = (): void => {
2152
2173
  uiTheme = resolveTheme(process.env);
2153
2174
  uiAccent = accentPaint(uiTheme);
@@ -2182,12 +2203,13 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
2182
2203
  // sits at the end of the text.
2183
2204
  const rli = rl as unknown as { line?: string; cursor?: number };
2184
2205
  const caret = rli.line === line && typeof rli.cursor === "number" ? rli.cursor : line.length;
2206
+ const { accent: boxAccent, shadow: boxShadow } = boxAccents(line);
2185
2207
  const frame = renderInputFrame(line, {
2186
2208
  cols,
2187
2209
  color: true,
2188
2210
  unicode: true,
2189
- accent: uiAccent,
2190
- accentShadow: uiAccentShadow,
2211
+ accent: boxAccent,
2212
+ accentShadow: boxShadow,
2191
2213
  cwdLabel: currentAtLabel(line),
2192
2214
  attachmentLabel: pendingImages.length
2193
2215
  ? `⧉ ${pendingImages.length} image${pendingImages.length > 1 ? "s" : ""} attached — sent with the next message`
@@ -3062,6 +3084,7 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
3062
3084
  history.length = 1;
3063
3085
  if (!flags.noSession) {
3064
3086
  sessionId = (await createSession(cwd)).id;
3087
+ advanceSessionBoxColor(); // distinct input-box hue per newly opened session
3065
3088
  console.log(`(${verb} — new session ${sessionId})`);
3066
3089
  } else {
3067
3090
  sessionId = undefined;
@@ -4115,6 +4138,25 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
4115
4138
  }
4116
4139
  continue;
4117
4140
  }
4141
+ // Unresolved `$skill` → suggest precisely, never silently send the typo to the model.
4142
+ // `$exact`/`$prefix` already ran above; a leftover `$word` is a missed skill attempt,
4143
+ // EXCEPT `$UPPERCASE` env-var-style tokens (e.g. `$HOME`), which pass through untouched.
4144
+ if (input.startsWith("$")) {
4145
+ const token = (input.split(/\s+/, 1)[0] ?? "").slice(1);
4146
+ if (token && !/^[A-Z_][A-Z0-9_]*$/.test(token)) {
4147
+ const lc = token.toLowerCase();
4148
+ const prefix = resolvedSkills.filter(s => s.name.toLowerCase().startsWith(lc));
4149
+ if (prefix.length) {
4150
+ console.log(`Ambiguous skill '$${token}'. Did you mean: ${prefix.slice(0, 6).map(s => `$${s.name}`).join(", ")}?`);
4151
+ } else {
4152
+ const names = resolvedSkills.map(s => `$${s.name}`);
4153
+ const shown = names.slice(0, 12).join(", ");
4154
+ const more = names.length > 12 ? ` … +${names.length - 12} more` : "";
4155
+ console.log(`No skill '$${token}'. ${names.length ? `Available: ${shown}${more}` : "No skills are loaded."} (Type $ to autocomplete.)`);
4156
+ }
4157
+ continue;
4158
+ }
4159
+ }
4118
4160
  // Unhandled slash attempt → suggest, don't send the typo to the model.
4119
4161
  if (isSlashAttempt(input)) {
4120
4162
  const m = matchSlash(input, [...completionContext().slashCommands]);
@@ -475,6 +475,32 @@ export function getSkillFrom(skills: SkillDoc[], name: string): SkillDoc | undef
475
475
  return skills.find(s => s.name.toLowerCase() === name.toLowerCase());
476
476
  }
477
477
 
478
+ /** The single skill whose name PREFIX-matches `query` (case-insensitive), or undefined
479
+ * when zero or many match. Lets `$te` precisely resolve to `$team` without full spelling. */
480
+ export function uniquePrefixSkill(skills: SkillDoc[], query: string): SkillDoc | undefined {
481
+ const q = query.toLowerCase();
482
+ if (!q) return undefined;
483
+ const hits = skills.filter(s => s.name.toLowerCase().startsWith(q));
484
+ return hits.length === 1 ? hits[0] : undefined;
485
+ }
486
+
487
+ /** Prefix-first, then fuzzy-subsequence skill suggestions for a `$query` that did NOT
488
+ * resolve — drives the REPL's clear "did you mean / available" feedback. */
489
+ export function suggestSkills(skills: SkillDoc[], query: string): SkillDoc[] {
490
+ const q = query.toLowerCase();
491
+ const prefix = skills.filter(s => s.name.toLowerCase().startsWith(q));
492
+ const seen = new Set(prefix.map(s => s.name));
493
+ const fuzzy = skills.filter(s => !seen.has(s.name) && skillNameSubsequence(q, s.name.toLowerCase()));
494
+ return [...prefix, ...fuzzy];
495
+ }
496
+
497
+ /** Order-preserving subsequence test (every char of `needle` appears in `hay` L→R). */
498
+ function skillNameSubsequence(needle: string, hay: string): boolean {
499
+ let i = 0;
500
+ for (let j = 0; j < hay.length && i < needle.length; j++) if (hay[j] === needle[i]) i++;
501
+ return i === needle.length;
502
+ }
503
+
478
504
  /** Case-insensitive lookup by direct slash alias, e.g. `/speckit.plan`. */
479
505
  export function getSkillBySlash(skills: SkillDoc[], command: string): SkillDoc | undefined {
480
506
  const q = command.toLowerCase();
@@ -514,7 +540,7 @@ export function parseSkillInvocation(input: string, skills: SkillDoc[]): SkillIn
514
540
  // only when a skill with that exact name is loaded — `$HOME is what?` or any
515
541
  // unknown `$word` falls through to the model as an ordinary prompt.
516
542
  if (command.length > 1 && command.startsWith("$")) {
517
- const dollarSkill = getSkillFrom(skills, command.slice(1));
543
+ const dollarSkill = getSkillFrom(skills, command.slice(1)) ?? uniquePrefixSkill(skills, command.slice(1));
518
544
  if (dollarSkill) {
519
545
  return { skill: dollarSkill, intent: trimmed.slice(command.length).trim(), invokedAs: command };
520
546
  }