From f1b7c3890ffdbdb441b4f42656eb73f1427ce939 Mon Sep 17 00:00:00 2001 From: zakiPoteto Date: Tue, 27 Oct 2026 14:44:26 +0900 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20whoami=E3=82=B3=E3=83=9E=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=82=92=E5=BE=A9=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- src/data/commands.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/data/commands.ts b/src/data/commands.ts index e70a2f5..58e907e 100644 --- a/src/data/commands.ts +++ b/src/data/commands.ts @@ -28,6 +28,7 @@ export function executeCommand(raw: string): CommandResult { switch (cmd) { case "about": + case "whoami": return { lines: [ ASCII_ART, @@ -188,7 +189,7 @@ export function executeCommand(raw: string): CommandResult { return { lines: [ "", - " about 自己紹介 + ASCII art", + " about | whoami 自己紹介 + ASCII art", " ls [-la1] [dir] ファイル一覧(-l 詳細 / -a 隠しファイル / -1 縦並び)", " cat [-n] ファイル表示(-n 行番号付き)", " open プロジェクトの GitHub を開く", @@ -217,7 +218,7 @@ const PROJECT_LINKS = Object.fromEntries( .map((e) => [e.slug!, { label: e.title, url: e.githubUrl! }]) ); -const KNOWN_COMMANDS = ["about", "ls", "cat", "open", "date", "echo", "clear", "exit", "help"]; +const KNOWN_COMMANDS = ["about", "whoami", "ls", "cat", "open", "date", "echo", "clear", "exit", "help"]; function levenshtein(a: string, b: string): number { const dp: number[][] = Array.from({ length: a.length + 1 }, (_, i) => From bc54bf4b9f073845d2365d86705661f9818de863 Mon Sep 17 00:00:00 2001 From: zakiPoteto Date: Tue, 27 Oct 2026 14:44:44 +0900 Subject: [PATCH 2/5] =?UTF-8?q?fix:=20=E6=9C=AA=E7=9F=A5=E3=81=AE=E3=83=95?= =?UTF-8?q?=E3=83=A9=E3=82=B0=E3=82=92=E3=82=A8=E3=83=A9=E3=83=BC=E3=81=AB?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- src/data/commands.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/data/commands.ts b/src/data/commands.ts index 58e907e..e34dbb4 100644 --- a/src/data/commands.ts +++ b/src/data/commands.ts @@ -8,17 +8,33 @@ export type CommandResult = { openUrl?: string; }; +// フラグを受け付けるコマンドと、許可する短縮フラグ・usage +const FLAG_SPECS: Record = { + ls: { allowed: "la1", usage: "ls [-la1] [dir]" }, + cat: { allowed: "n", usage: "cat [-n] " }, + open: { allowed: "", usage: "open " }, +}; + export function executeCommand(raw: string): CommandResult { const parts = raw.trim().split(/\s+/); const cmd = parts[0].toLowerCase(); + const spec = FLAG_SPECS[cmd]; + + const illegalOption = (opt: string): CommandResult => ({ + lines: [`${cmd}: illegal option -- ${opt}`, `usage: ${spec.usage}`], + }); const flags = new Set(); const args: string[] = []; for (const p of parts.slice(1)) { if (p.startsWith("--")) { + if (spec) return illegalOption(p); flags.add(p.slice(2)); } else if (p.startsWith("-") && p.length > 1) { - for (const ch of p.slice(1)) flags.add(ch); + for (const ch of p.slice(1)) { + if (spec && !spec.allowed.includes(ch)) return illegalOption(ch); + flags.add(ch); + } } else { args.push(p.toLowerCase()); } From f741b7f0316fb751b1930f075c8020a758f59bc9 Mon Sep 17 00:00:00 2001 From: zakiPoteto Date: Tue, 27 Oct 2026 14:45:31 +0900 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20ls=20-l=E3=81=AE=E5=88=97=E3=81=9A?= =?UTF-8?q?=E3=82=8C=E3=81=A8=E3=82=B7=E3=83=A3=E3=83=89=E3=83=BC=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=82=B0=E8=A7=A3=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- src/data/commands.ts | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/data/commands.ts b/src/data/commands.ts index e34dbb4..6d726fb 100644 --- a/src/data/commands.ts +++ b/src/data/commands.ts @@ -8,6 +8,23 @@ export type CommandResult = { openUrl?: string; }; +const PROJECT_LINKS = Object.fromEntries( + experiences + .filter((e) => e.slug && e.githubUrl) + .map((e) => [e.slug!, { label: e.title, url: e.githubUrl! }]) +); + +const KNOWN_COMMANDS = ["about", "whoami", "ls", "cat", "open", "date", "echo", "clear", "exit", "help"]; + +// 全角文字を幅2として数えた表示幅(等幅フォントで列を揃えるため) +const WIDE_CHAR = /[ᄀ-ᅟ⺀-꓏가-힣豈-﫿︰-﹯＀-⦆¢-₩]/; + +function displayWidth(s: string): number { + let width = 0; + for (const ch of s) width += WIDE_CHAR.test(ch) ? 2 : 1; + return width; +} + // フラグを受け付けるコマンドと、許可する短縮フラグ・usage const FLAG_SPECS: Record = { ls: { allowed: "la1", usage: "ls [-la1] [dir]" }, @@ -65,12 +82,14 @@ export function executeCommand(raw: string): CommandResult { if (sub === "projects") { if (long) { + const dateWidth = Math.max(...experiences.map((e) => displayWidth(e.date))); return { lines: [ "", `total ${experiences.length}`, ...experiences.map( - (e) => `drwxr-xr-x zaki ${e.date.padEnd(16)} ${e.title}` + (e) => + `drwxr-xr-x zaki ${e.date}${" ".repeat(dateWidth - displayWidth(e.date))} ${e.title}` ), "", ], @@ -100,7 +119,7 @@ export function executeCommand(raw: string): CommandResult { lines: [ "", `total ${files.length}`, - ...files.map((f) => `${perms(f)} zaki ${date} ${f}`), + ...files.map((name) => `${perms(name)} zaki ${date} ${name}`), "", ], }; @@ -228,14 +247,6 @@ export function executeCommand(raw: string): CommandResult { } } -const PROJECT_LINKS = Object.fromEntries( - experiences - .filter((e) => e.slug && e.githubUrl) - .map((e) => [e.slug!, { label: e.title, url: e.githubUrl! }]) -); - -const KNOWN_COMMANDS = ["about", "whoami", "ls", "cat", "open", "date", "echo", "clear", "exit", "help"]; - function levenshtein(a: string, b: string): number { const dp: number[][] = Array.from({ length: a.length + 1 }, (_, i) => Array.from({ length: b.length + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)) From f1ead4ad277ab72e7c1618f4ad5d334e1aa75d71 Mon Sep 17 00:00:00 2001 From: zakiPoteto Date: Tue, 27 Oct 2026 14:49:46 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=E7=B6=99=E6=89=BF=E3=82=AD=E3=83=BC?= =?UTF-8?q?=E3=81=A7=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89=E3=81=8C=E8=90=BD?= =?UTF-8?q?=E3=81=A1=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- src/data/commands.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/data/commands.ts b/src/data/commands.ts index 6d726fb..545d764 100644 --- a/src/data/commands.ts +++ b/src/data/commands.ts @@ -35,21 +35,21 @@ const FLAG_SPECS: Record = { export function executeCommand(raw: string): CommandResult { const parts = raw.trim().split(/\s+/); const cmd = parts[0].toLowerCase(); - const spec = FLAG_SPECS[cmd]; + const spec = Object.hasOwn(FLAG_SPECS, cmd) ? FLAG_SPECS[cmd] : undefined; - const illegalOption = (opt: string): CommandResult => ({ - lines: [`${cmd}: illegal option -- ${opt}`, `usage: ${spec.usage}`], + const illegalOption = (opt: string, usage: string): CommandResult => ({ + lines: [`${cmd}: illegal option -- ${opt}`, `usage: ${usage}`], }); const flags = new Set(); const args: string[] = []; for (const p of parts.slice(1)) { if (p.startsWith("--")) { - if (spec) return illegalOption(p); + if (spec) return illegalOption(p, spec.usage); flags.add(p.slice(2)); } else if (p.startsWith("-") && p.length > 1) { for (const ch of p.slice(1)) { - if (spec && !spec.allowed.includes(ch)) return illegalOption(ch); + if (spec && !spec.allowed.includes(ch)) return illegalOption(ch, spec.usage); flags.add(ch); } } else { @@ -191,7 +191,7 @@ export function executeCommand(raw: string): CommandResult { } case "open": { - const project = PROJECT_LINKS[sub ?? ""]; + const project = sub && Object.hasOwn(PROJECT_LINKS, sub) ? PROJECT_LINKS[sub] : undefined; if (project) { return { lines: [`Opening ${project.label} on GitHub...`], From fa7114a6d569c833c783549e8d741d18a1fd4e36 Mon Sep 17 00:00:00 2001 From: zakiPoteto Date: Tue, 27 Oct 2026 14:49:57 +0900 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20=E7=B5=8C=E9=A8=93=E3=81=8C=E7=A9=BA?= =?UTF-8?q?=E3=81=A7=E3=82=82ls=20-l=E3=81=8C=E8=90=BD=E3=81=A1=E3=81=AA?= =?UTF-8?q?=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- src/data/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/commands.ts b/src/data/commands.ts index 545d764..64f514d 100644 --- a/src/data/commands.ts +++ b/src/data/commands.ts @@ -82,7 +82,7 @@ export function executeCommand(raw: string): CommandResult { if (sub === "projects") { if (long) { - const dateWidth = Math.max(...experiences.map((e) => displayWidth(e.date))); + const dateWidth = Math.max(0, ...experiences.map((e) => displayWidth(e.date))); return { lines: [ "",