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 +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/package.json +1 -1
- package/src/commands/launch.ts +44 -2
- package/src/skills/catalog.ts +27 -1
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
package/src/commands/launch.ts
CHANGED
|
@@ -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:
|
|
2190
|
-
accentShadow:
|
|
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]);
|
package/src/skills/catalog.ts
CHANGED
|
@@ -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
|
}
|