terminal-quest 1.0.2 → 1.1.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.md +43 -4
- package/dist/App.js +1 -1
- package/dist/data/stories/00-beginner-pc.js +70 -0
- package/dist/data/stories/01-first-server.js +77 -0
- package/dist/data/stories/02-messy-project.js +24 -0
- package/dist/data/stories/03-log-detective.js +4 -0
- package/dist/data/stories/04-deploy-day.js +4 -0
- package/dist/data/stories/05-git-incident.js +5 -0
- package/dist/data/stories/06-pipe-master.js +4 -0
- package/dist/data/stories/07-dangerous-commands.js +4 -0
- package/dist/data/stories/k1-treasure-hunt.js +181 -0
- package/dist/data/types.d.ts +14 -0
- package/dist/engine/CommandFeedback.d.ts +14 -0
- package/dist/engine/CommandFeedback.js +55 -0
- package/dist/engine/commands/grep.js +42 -17
- package/dist/engine/commands/wc.js +50 -21
- package/dist/screens/MissionBriefScreen.js +3 -3
- package/dist/screens/MissionCompleteScreen.d.ts +2 -1
- package/dist/screens/MissionCompleteScreen.js +37 -12
- package/dist/screens/TerminalScreen.d.ts +1 -1
- package/dist/screens/TerminalScreen.js +47 -7
- package/dist/state/useGameState.d.ts +1 -1
- package/dist/state/useGameState.js +5 -1
- package/package.json +1 -1
|
@@ -239,6 +239,7 @@ export const story07 = {
|
|
|
239
239
|
missions: [
|
|
240
240
|
{
|
|
241
241
|
id: 'mission-07-01',
|
|
242
|
+
goal: '削除前に ls と cat で中身を確認する習慣を身につける',
|
|
242
243
|
title: '\u3046\u3063\u304B\u308A\u524A\u9664',
|
|
243
244
|
description: '\u30D5\u30A1\u30A4\u30EB\u3092\u524A\u9664\u3059\u308B\u524D\u306B\u3001\u307E\u305A\u4E2D\u8EAB\u3092\u78BA\u8A8D\u3059\u308B\u7FD2\u6163\u3092\u3064\u3051\u3088\u3046\u3002',
|
|
244
245
|
narrative: '\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306B\u4E0D\u8981\u306A\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u30D5\u30A1\u30A4\u30EB\u304C\u6B8B\u3063\u3066\u3044\u308B\u3089\u3057\u3044\u3002\u3067\u3082\u524A\u9664\u3059\u308B\u524D\u306B\u3001\u307E\u305A\u4F55\u304C\u3042\u308B\u304B\u78BA\u8A8D\u3057\u3088\u3046\u3002\u91CD\u8981\u306A\u30D5\u30A1\u30A4\u30EB\u3092\u9593\u9055\u3048\u3066\u524A\u9664\u3057\u305F\u3089\u5927\u5909\u3060\uFF01',
|
|
@@ -282,6 +283,7 @@ export const story07 = {
|
|
|
282
283
|
},
|
|
283
284
|
{
|
|
284
285
|
id: 'mission-07-02',
|
|
286
|
+
goal: '削除する前にバックアップを取る安全な運用手順を身につける',
|
|
285
287
|
title: '\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u306E\u6975\u610F',
|
|
286
288
|
description: '\u524A\u9664\u3059\u308B\u524D\u306B\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3092\u53D6\u308B\u7FD2\u6163\u3092\u8EAB\u306B\u3064\u3051\u3088\u3046\u3002',
|
|
287
289
|
narrative: '\u30B5\u30FC\u30D0\u30FC\u306E\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u3092\u6574\u7406\u3059\u308B\u3053\u3068\u306B\u306A\u3063\u305F\u3002\u3067\u3082\u3044\u304D\u306A\u308A\u524A\u9664\u3059\u308B\u306E\u306F\u5371\u967A\u3060\u3002\u307E\u305A\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3092\u53D6\u3063\u3066\u304B\u3089\u3001\u4E0D\u8981\u306A\u30D5\u30A1\u30A4\u30EB\u3092\u524A\u9664\u3057\u3088\u3046\u3002',
|
|
@@ -325,6 +327,7 @@ export const story07 = {
|
|
|
325
327
|
},
|
|
326
328
|
{
|
|
327
329
|
id: 'mission-07-03',
|
|
330
|
+
goal: 'rm -rf の威力を理解し、正しい対象だけを削除できるようになる',
|
|
328
331
|
title: 'rm -rf \u306E\u6B63\u4F53',
|
|
329
332
|
description: 'rm -rf \u306E\u5A01\u529B\u3092\u7406\u89E3\u3057\u3001\u6B63\u3057\u3044\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3060\u3051\u3092\u524A\u9664\u3057\u3088\u3046\u3002',
|
|
330
333
|
narrative: '\u30D3\u30EB\u30C9\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u6563\u3089\u304B\u3063\u3066\u3044\u308B\u3002\u53E4\u3044\u30D3\u30EB\u30C9\u7D50\u679C\u3092 rm -rf \u3067\u524A\u9664\u3057\u305F\u3044\u304C\u3001\u9593\u9055\u3048\u3066\u30BD\u30FC\u30B9\u30B3\u30FC\u30C9\u3092\u524A\u9664\u3057\u305F\u3089\u53D6\u308A\u8FD4\u3057\u304C\u3064\u304B\u306A\u3044\u3002\u307E\u305A\u4E2D\u8EAB\u3092\u78BA\u8A8D\u3057\u3066\u304B\u3089\u524A\u9664\u3057\u3088\u3046\u3002',
|
|
@@ -365,6 +368,7 @@ export const story07 = {
|
|
|
365
368
|
},
|
|
366
369
|
{
|
|
367
370
|
id: 'mission-07-04',
|
|
371
|
+
goal: 'find で削除対象を事前確認してから安全に削除するワークフローを習得する',
|
|
368
372
|
title: '\u5B89\u5168\u306A\u7FD2\u6163',
|
|
369
373
|
description: 'find \u3067\u524A\u9664\u5BFE\u8C61\u3092\u78BA\u8A8D\u3057\u3066\u304B\u3089\u3001\u5B89\u5168\u306B\u524A\u9664\u3057\u3088\u3046\u3002',
|
|
370
374
|
narrative: '\u30ED\u30B0\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306B\u53E4\u3044\u30ED\u30B0\u30D5\u30A1\u30A4\u30EB\u304C\u6EA2\u308C\u3066\u3044\u308B\u3002\u53E4\u3044\u6708\u6B21\u30ED\u30B0\u3092\u524A\u9664\u3057\u3066\u6574\u7406\u3057\u305F\u3044\u304C\u3001error.log \u3084 access.log \u306F\u6D88\u3057\u3066\u306F\u3044\u3051\u306A\u3044\u3002\u307E\u305A find \u3067\u524A\u9664\u5BFE\u8C61\u3092\u7D5E\u308A\u8FBC\u3082\u3046\u3002',
|
|
@@ -378,6 +378,13 @@ export const storyK1 = {
|
|
|
378
378
|
id: 'mission-k1-01',
|
|
379
379
|
title: '冒険のはじまり',
|
|
380
380
|
description: 'いまいる場所をたしかめて、まわりを見てみよう!',
|
|
381
|
+
goal: 'pwd と ls をつかって、いまいる場所とまわりにあるものがわかるようになる',
|
|
382
|
+
review: {
|
|
383
|
+
question: 'いまいるばしょをひょうじするコマンドはどれかな?',
|
|
384
|
+
choices: ['ls', 'cd', 'pwd'],
|
|
385
|
+
correctIndex: 2,
|
|
386
|
+
explanation: 'pwd はいまいるばしょ(ディレクトリ)をひょうじするコマンドだよ。「Print Working Directory」のりゃくだよ。',
|
|
387
|
+
},
|
|
381
388
|
narrative: 'きみは冒険の世界にやってきた!スタート地点にいるみたいだけど、ここはどこだろう?まずは「いまいる場所」をたしかめて、まわりに何があるか見てみよう。',
|
|
382
389
|
initialCwd: '/冒険の世界/スタート地点',
|
|
383
390
|
initialFS: mission1FS,
|
|
@@ -392,6 +399,11 @@ export const storyK1 = {
|
|
|
392
399
|
{ level: 2, text: '「pwd」っていう3文字のコマンドだよ。' },
|
|
393
400
|
{ level: 3, text: '「pwd」とにゅうりょくして Enter をおしてね。' },
|
|
394
401
|
],
|
|
402
|
+
feedbacks: [
|
|
403
|
+
{ pattern: 'ls', message: 'ls はまわりを見るコマンドだよ。いまいる場所をしるには、べつのコマンドをつかうよ。' },
|
|
404
|
+
{ pattern: 'cd', message: 'cd はべつの場所にいどうするコマンドだよ。いまいる場所をたしかめるには、べつのコマンドをつかうよ。' },
|
|
405
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。いまいる場所をしるには、べつのコマンドをつかうよ。' },
|
|
406
|
+
],
|
|
395
407
|
},
|
|
396
408
|
{
|
|
397
409
|
id: 'obj-k1-01-02',
|
|
@@ -402,6 +414,11 @@ export const storyK1 = {
|
|
|
402
414
|
{ level: 2, text: '「ls」っていう2文字のコマンドだよ。' },
|
|
403
415
|
{ level: 3, text: '「ls」とにゅうりょくして Enter をおしてね。' },
|
|
404
416
|
],
|
|
417
|
+
feedbacks: [
|
|
418
|
+
{ pattern: 'pwd', message: 'pwd はいまいる場所をひょうじするコマンドだよ。まわりを見るには、べつのコマンドをつかうよ。' },
|
|
419
|
+
{ pattern: 'cd', message: 'cd はべつの場所にいどうするコマンドだよ。まわりにあるものを見るには、べつのコマンドをつかうよ。' },
|
|
420
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。まわりにあるものを見るには、べつのコマンドをつかうよ。' },
|
|
421
|
+
],
|
|
405
422
|
},
|
|
406
423
|
],
|
|
407
424
|
},
|
|
@@ -410,6 +427,13 @@ export const storyK1 = {
|
|
|
410
427
|
id: 'mission-k1-02',
|
|
411
428
|
title: '森を冒険しよう',
|
|
412
429
|
description: '魔法の森にいって、古い巻物を読んでみよう!',
|
|
430
|
+
goal: 'cd でべつの場所にいどうし、cat でファイルを読めるようになる',
|
|
431
|
+
review: {
|
|
432
|
+
question: 'べつのばしょにいどうするコマンドはどれかな?',
|
|
433
|
+
choices: ['pwd', 'ls', 'cd', 'cat'],
|
|
434
|
+
correctIndex: 2,
|
|
435
|
+
explanation: 'cd はべつのばしょ(ディレクトリ)にいどうするコマンドだよ。「Change Directory」のりゃくだよ。',
|
|
436
|
+
},
|
|
413
437
|
narrative: '案内板に「魔法の森には何かひみつがある」と書いてあった。森にいって、手がかりをさがそう!巻物を読んだら、スタート地点にもどってこよう。',
|
|
414
438
|
initialCwd: '/冒険の世界/スタート地点',
|
|
415
439
|
initialFS: mission2FS,
|
|
@@ -424,6 +448,11 @@ export const storyK1 = {
|
|
|
424
448
|
{ level: 2, text: '「cd」のあとに、いきたい場所の名前を書くよ。' },
|
|
425
449
|
{ level: 3, text: '「cd /冒険の世界/魔法の森」とにゅうりょくしてね。' },
|
|
426
450
|
],
|
|
451
|
+
feedbacks: [
|
|
452
|
+
{ pattern: 'pwd', message: 'pwd はいまいる場所をたしかめるコマンドだよ。べつの場所にいくには、いどうするコマンドをつかうよ。' },
|
|
453
|
+
{ pattern: 'ls', message: 'ls はまわりにあるものを見るコマンドだよ。べつの場所にいくには、いどうするコマンドをつかうよ。' },
|
|
454
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。べつの場所にいくには、いどうするコマンドをつかうよ。' },
|
|
455
|
+
],
|
|
427
456
|
},
|
|
428
457
|
{
|
|
429
458
|
id: 'obj-k1-02-02',
|
|
@@ -434,6 +463,11 @@ export const storyK1 = {
|
|
|
434
463
|
{ level: 2, text: '「cat」のあとにファイル名を書くと、中身が読めるよ。' },
|
|
435
464
|
{ level: 3, text: '「cat 古い巻物.txt」とにゅうりょくしてね。' },
|
|
436
465
|
],
|
|
466
|
+
feedbacks: [
|
|
467
|
+
{ pattern: 'pwd', message: 'pwd はいまいる場所をたしかめるコマンドだよ。ファイルの中身を読むには、べつのコマンドをつかうよ。' },
|
|
468
|
+
{ pattern: 'ls', message: 'ls はまわりにあるものを見るコマンドだよ。ファイルの中身を読むには、べつのコマンドをつかうよ。' },
|
|
469
|
+
{ pattern: 'cd', message: 'cd はべつの場所にいどうするコマンドだよ。ファイルの中身を読むには、べつのコマンドをつかうよ。' },
|
|
470
|
+
],
|
|
437
471
|
},
|
|
438
472
|
{
|
|
439
473
|
id: 'obj-k1-02-03',
|
|
@@ -444,6 +478,11 @@ export const storyK1 = {
|
|
|
444
478
|
{ level: 2, text: 'スタート地点のフルパスを指定しよう。' },
|
|
445
479
|
{ level: 3, text: '「cd /冒険の世界/スタート地点」とにゅうりょくしてね。' },
|
|
446
480
|
],
|
|
481
|
+
feedbacks: [
|
|
482
|
+
{ pattern: 'pwd', message: 'pwd はいまいる場所をたしかめるコマンドだよ。もどるには、いどうするコマンドをつかうよ。' },
|
|
483
|
+
{ pattern: 'ls', message: 'ls はまわりにあるものを見るコマンドだよ。もどるには、いどうするコマンドをつかうよ。' },
|
|
484
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。もどるには、いどうするコマンドをつかうよ。' },
|
|
485
|
+
],
|
|
447
486
|
},
|
|
448
487
|
],
|
|
449
488
|
},
|
|
@@ -452,6 +491,13 @@ export const storyK1 = {
|
|
|
452
491
|
id: 'mission-k1-03',
|
|
453
492
|
title: '秘密基地を作ろう',
|
|
454
493
|
description: 'じぶんだけの秘密基地をつくろう!部屋もつくって、ノートもおこう。',
|
|
494
|
+
goal: 'mkdir でフォルダをつくり、touch でファイルをつくれるようになる',
|
|
495
|
+
review: {
|
|
496
|
+
question: 'あたらしいフォルダをつくるコマンドはどれかな?',
|
|
497
|
+
choices: ['touch', 'mkdir', 'rm', 'ls'],
|
|
498
|
+
correctIndex: 1,
|
|
499
|
+
explanation: 'mkdir はあたらしいフォルダ(ディレクトリ)をつくるコマンドだよ。「Make Directory」のりゃくだよ。',
|
|
500
|
+
},
|
|
455
501
|
narrative: '冒険には秘密基地がひつようだ!まずは基地をつくって、たからものをしまう部屋と、冒険のきろくをつけるノートを用意しよう。',
|
|
456
502
|
initialCwd: '/冒険の世界',
|
|
457
503
|
initialFS: mission3FS,
|
|
@@ -466,6 +512,11 @@ export const storyK1 = {
|
|
|
466
512
|
{ level: 2, text: '「mkdir」のあとにフォルダの名前を書くよ。' },
|
|
467
513
|
{ level: 3, text: '「mkdir 秘密基地」とにゅうりょくしてね。' },
|
|
468
514
|
],
|
|
515
|
+
feedbacks: [
|
|
516
|
+
{ pattern: 'touch', message: 'touch はからっぽのファイルをつくるコマンドだよ。フォルダをつくるには、べつのコマンドをつかうよ。' },
|
|
517
|
+
{ pattern: 'ls', message: 'ls はまわりにあるものを見るコマンドだよ。あたらしいフォルダをつくるには、べつのコマンドをつかうよ。' },
|
|
518
|
+
{ pattern: 'cd', message: 'cd はべつの場所にいどうするコマンドだよ。あたらしいフォルダをつくるには、べつのコマンドをつかうよ。' },
|
|
519
|
+
],
|
|
469
520
|
},
|
|
470
521
|
{
|
|
471
522
|
id: 'obj-k1-03-02',
|
|
@@ -476,6 +527,10 @@ export const storyK1 = {
|
|
|
476
527
|
{ level: 2, text: '「mkdir」でパスを指定して、中にフォルダがつくれるよ。' },
|
|
477
528
|
{ level: 3, text: '「mkdir 秘密基地/宝物庫」とにゅうりょくしてね。' },
|
|
478
529
|
],
|
|
530
|
+
feedbacks: [
|
|
531
|
+
{ pattern: 'touch', message: 'touch はファイルをつくるコマンドだよ。フォルダをつくるには、さっきとおなじコマンドをつかうよ。' },
|
|
532
|
+
{ pattern: 'cd', message: 'cd はいどうするコマンドだよ。フォルダをつくるには、さっきつかったコマンドをもういちどつかおう。' },
|
|
533
|
+
],
|
|
479
534
|
},
|
|
480
535
|
{
|
|
481
536
|
id: 'obj-k1-03-03',
|
|
@@ -488,6 +543,11 @@ export const storyK1 = {
|
|
|
488
543
|
{ level: 2, text: '「touch」のあとにファイル名を書くと、ファイルがつくれるよ。' },
|
|
489
544
|
{ level: 3, text: '「touch 秘密基地/冒険ノート.txt」とにゅうりょくしてね。' },
|
|
490
545
|
],
|
|
546
|
+
feedbacks: [
|
|
547
|
+
{ pattern: 'mkdir', message: 'mkdir はフォルダをつくるコマンドだよ。からっぽのファイルをつくるには、べつのコマンドをつかうよ。' },
|
|
548
|
+
{ pattern: 'echo', message: 'echo はもじをひょうじするコマンドだよ。からっぽのファイルをつくるには、べつのコマンドをつかうよ。' },
|
|
549
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。からっぽのファイルをつくるには、べつのコマンドをつかうよ。' },
|
|
550
|
+
],
|
|
491
551
|
},
|
|
492
552
|
],
|
|
493
553
|
},
|
|
@@ -496,6 +556,13 @@ export const storyK1 = {
|
|
|
496
556
|
id: 'mission-k1-04',
|
|
497
557
|
title: '宝物を集めよう',
|
|
498
558
|
description: 'いろんな場所にある宝物を秘密基地にあつめよう!',
|
|
559
|
+
goal: 'cp でコピー、mv でいどうができるようになる',
|
|
560
|
+
review: {
|
|
561
|
+
question: 'ファイルをコピーするコマンドはどれかな?',
|
|
562
|
+
choices: ['mv', 'cp', 'rm', 'cat'],
|
|
563
|
+
correctIndex: 1,
|
|
564
|
+
explanation: 'cp はファイルをコピーするコマンドだよ。もとのファイルはそのままのこるよ。「copy」のりゃくだよ。',
|
|
565
|
+
},
|
|
499
566
|
narrative: '冒険の世界にはたからものがいっぱい!魔法の森にある宝石をコピーして、古いお城にある伝説の剣を秘密基地にうつそう。',
|
|
500
567
|
initialCwd: '/冒険の世界',
|
|
501
568
|
initialFS: mission4FS,
|
|
@@ -518,6 +585,11 @@ export const storyK1 = {
|
|
|
518
585
|
text: '「cp 魔法の森/光る宝石.txt 秘密基地/宝物庫/光る宝石.txt」とにゅうりょくしてね。',
|
|
519
586
|
},
|
|
520
587
|
],
|
|
588
|
+
feedbacks: [
|
|
589
|
+
{ pattern: 'mv', message: 'mv はファイルをいどうするコマンドだよ。コピーするには、もとのファイルをのこしたままつくるコマンドをつかうよ。' },
|
|
590
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。ファイルをコピーするには、べつのコマンドをつかうよ。' },
|
|
591
|
+
{ pattern: 'rm', message: 'rm はファイルをけすコマンドだよ。コピーするには、べつのコマンドをつかうよ。' },
|
|
592
|
+
],
|
|
521
593
|
},
|
|
522
594
|
{
|
|
523
595
|
id: 'obj-k1-04-02',
|
|
@@ -536,6 +608,11 @@ export const storyK1 = {
|
|
|
536
608
|
text: '「mv 古いお城/宝物庫/伝説の剣.txt 秘密基地/宝物庫/伝説の剣.txt」とにゅうりょくしてね。',
|
|
537
609
|
},
|
|
538
610
|
],
|
|
611
|
+
feedbacks: [
|
|
612
|
+
{ pattern: 'cp', message: 'cp はコピーするコマンドだよ。もとのファイルをなくして、べつの場所にうつすには、べつのコマンドをつかうよ。' },
|
|
613
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。ファイルをうつすには、べつのコマンドをつかうよ。' },
|
|
614
|
+
{ pattern: 'rm', message: 'rm はファイルをけすコマンドだよ。うつすには、けすのではなくいどうするコマンドをつかうよ。' },
|
|
615
|
+
],
|
|
539
616
|
},
|
|
540
617
|
],
|
|
541
618
|
},
|
|
@@ -544,6 +621,13 @@ export const storyK1 = {
|
|
|
544
621
|
id: 'mission-k1-05',
|
|
545
622
|
title: 'トラップを片付けよう',
|
|
546
623
|
description: 'ひみつの洞窟にしかけられたトラップを見つけて、かたづけよう!',
|
|
624
|
+
goal: 'find でファイルをさがし、rm でけせるようになる',
|
|
625
|
+
review: {
|
|
626
|
+
question: 'ファイルをけすコマンドはどれかな?',
|
|
627
|
+
choices: ['cp', 'mv', 'rm', 'find'],
|
|
628
|
+
correctIndex: 2,
|
|
629
|
+
explanation: 'rm はファイルをけすコマンドだよ。「remove」のりゃくだよ。けしたファイルはもとにもどせないから、きをつけてつかおうね。',
|
|
630
|
+
},
|
|
547
631
|
narrative: 'ひみつの洞窟にはトラップがしかけてある!まずはトラップがどこにあるか見つけて、ぜんぶかたづけよう。そうすれば安全にたからものがとれるよ。',
|
|
548
632
|
initialCwd: '/冒険の世界/ひみつの洞窟',
|
|
549
633
|
initialFS: mission5FS,
|
|
@@ -561,6 +645,11 @@ export const storyK1 = {
|
|
|
561
645
|
text: '「find . -name トラップ*」とにゅうりょくしてね。',
|
|
562
646
|
},
|
|
563
647
|
],
|
|
648
|
+
feedbacks: [
|
|
649
|
+
{ pattern: 'ls', message: 'ls はいまいるフォルダの中身を見るコマンドだよ。おくのフォルダもふくめてさがすには、べつのコマンドをつかうよ。' },
|
|
650
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。ファイルをさがすには、べつのコマンドをつかうよ。' },
|
|
651
|
+
{ pattern: 'grep', message: 'grep はファイルの中のことばをさがすコマンドだよ。ファイルの名前でさがすには、べつのコマンドをつかうよ。' },
|
|
652
|
+
],
|
|
564
653
|
},
|
|
565
654
|
{
|
|
566
655
|
id: 'obj-k1-05-02',
|
|
@@ -576,6 +665,10 @@ export const storyK1 = {
|
|
|
576
665
|
{ level: 2, text: '「rm」のあとにけしたいファイル名を書くよ。' },
|
|
577
666
|
{ level: 3, text: '「rm トラップ1.txt」とにゅうりょくしてね。' },
|
|
578
667
|
],
|
|
668
|
+
feedbacks: [
|
|
669
|
+
{ pattern: 'mv', message: 'mv はファイルをいどうするコマンドだよ。ファイルをけすには、べつのコマンドをつかうよ。' },
|
|
670
|
+
{ pattern: 'find', message: 'find はファイルをさがすコマンドだよ。もうみつけたから、つぎはけすコマンドをつかおう。' },
|
|
671
|
+
],
|
|
579
672
|
},
|
|
580
673
|
{
|
|
581
674
|
id: 'obj-k1-05-03',
|
|
@@ -591,6 +684,9 @@ export const storyK1 = {
|
|
|
591
684
|
{ level: 2, text: '「rm」コマンドをつかおう。' },
|
|
592
685
|
{ level: 3, text: '「rm トラップ2.txt」とにゅうりょくしてね。' },
|
|
593
686
|
],
|
|
687
|
+
feedbacks: [
|
|
688
|
+
{ pattern: 'mv', message: 'mv はいどうするコマンドだよ。けすには、さっきとおなじコマンドをつかおう。' },
|
|
689
|
+
],
|
|
594
690
|
},
|
|
595
691
|
{
|
|
596
692
|
id: 'obj-k1-05-04',
|
|
@@ -606,6 +702,9 @@ export const storyK1 = {
|
|
|
606
702
|
{ level: 2, text: 'パスを指定すればべつのフォルダの中のファイルもけせるよ。' },
|
|
607
703
|
{ level: 3, text: '「rm 奥の部屋/トラップ3.txt」とにゅうりょくしてね。' },
|
|
608
704
|
],
|
|
705
|
+
feedbacks: [
|
|
706
|
+
{ pattern: 'cd', message: 'cd でいどうしなくても、パスをしていすればべつのフォルダの中のファイルもけせるよ。' },
|
|
707
|
+
],
|
|
609
708
|
},
|
|
610
709
|
],
|
|
611
710
|
},
|
|
@@ -614,6 +713,13 @@ export const storyK1 = {
|
|
|
614
713
|
id: 'mission-k1-06',
|
|
615
714
|
title: '暗号を解読しよう',
|
|
616
715
|
description: '暗号文から手がかりをさがして、けっかを書きのこそう!',
|
|
716
|
+
goal: 'grep でことばをさがし、echo でファイルに書きこめるようになる',
|
|
717
|
+
review: {
|
|
718
|
+
question: 'ファイルの中からことばをさがすコマンドはどれかな?',
|
|
719
|
+
choices: ['find', 'cat', 'grep', 'echo'],
|
|
720
|
+
correctIndex: 2,
|
|
721
|
+
explanation: 'grep はファイルの中からことばをさがすコマンドだよ。find がファイルの「名前」をさがすのにたいして、grep はファイルの「中身」をさがすよ。',
|
|
722
|
+
},
|
|
617
723
|
narrative: '洞窟のおくで暗号文を見つけた!この中に「魔法」というキーワードがかくれているらしい。さがしだして、わかったことを書きのこそう。',
|
|
618
724
|
initialCwd: '/冒険の世界/ひみつの洞窟',
|
|
619
725
|
initialFS: mission6FS,
|
|
@@ -628,6 +734,10 @@ export const storyK1 = {
|
|
|
628
734
|
{ level: 2, text: '「grep」のあとにさがしたいことばとファイル名を書くよ。' },
|
|
629
735
|
{ level: 3, text: '「grep 魔法 暗号文.txt」とにゅうりょくしてね。' },
|
|
630
736
|
],
|
|
737
|
+
feedbacks: [
|
|
738
|
+
{ pattern: 'cat', message: 'cat はファイルのぜんぶを読むコマンドだよ。とくていのことばだけさがすには、べつのコマンドをつかうよ。' },
|
|
739
|
+
{ pattern: 'find', message: 'find はファイルの名前をさがすコマンドだよ。ファイルの中身からことばをさがすには、べつのコマンドをつかうよ。' },
|
|
740
|
+
],
|
|
631
741
|
},
|
|
632
742
|
{
|
|
633
743
|
id: 'obj-k1-06-02',
|
|
@@ -646,6 +756,10 @@ export const storyK1 = {
|
|
|
646
756
|
text: '「echo "魔法使いが宝の地図をくれた" > 解読結果.txt」とにゅうりょくしてね。',
|
|
647
757
|
},
|
|
648
758
|
],
|
|
759
|
+
feedbacks: [
|
|
760
|
+
{ pattern: 'touch', message: 'touch はからっぽのファイルをつくるコマンドだよ。中身もいっしょに書きこむには、べつのコマンドと「>」をつかうよ。' },
|
|
761
|
+
{ pattern: 'cat', message: 'cat はファイルを読むコマンドだよ。ファイルに書きこむには、べつのコマンドと「>」をつかうよ。' },
|
|
762
|
+
],
|
|
649
763
|
},
|
|
650
764
|
],
|
|
651
765
|
},
|
|
@@ -654,6 +768,13 @@ export const storyK1 = {
|
|
|
654
768
|
id: 'mission-k1-07',
|
|
655
769
|
title: '古い書物を読もう',
|
|
656
770
|
description: 'ながい魔法の書の最初と最後をかくにんして、何ページあるかかぞえよう!',
|
|
771
|
+
goal: 'head と tail でファイルの一部を読み、wc で行数をかぞえられるようになる',
|
|
772
|
+
review: {
|
|
773
|
+
question: 'ファイルのさいしょの方だけ読むコマンドはどれかな?',
|
|
774
|
+
choices: ['cat', 'head', 'tail', 'wc'],
|
|
775
|
+
correctIndex: 1,
|
|
776
|
+
explanation: 'head はファイルのさいしょの方だけひょうじするコマンドだよ。さいごの方を見るには tail をつかうよ。',
|
|
777
|
+
},
|
|
657
778
|
narrative: '古いお城の図書室で、ぶあつい魔法の書を見つけた!ぜんぶ読むのは大変だから、最初と最後だけ読んで、ページ数もかくにんしよう。',
|
|
658
779
|
initialCwd: '/冒険の世界/古いお城/図書室',
|
|
659
780
|
initialFS: mission7FS,
|
|
@@ -668,6 +789,10 @@ export const storyK1 = {
|
|
|
668
789
|
{ level: 2, text: '「head」コマンドをつかうと、ファイルのさいしょの方だけ見られるよ。' },
|
|
669
790
|
{ level: 3, text: '「head 魔法の書.txt」とにゅうりょくしてね。' },
|
|
670
791
|
],
|
|
792
|
+
feedbacks: [
|
|
793
|
+
{ pattern: 'cat', message: 'cat はファイルのぜんぶをひょうじするよ。さいしょの方だけ見るには、べつのコマンドをつかうよ。' },
|
|
794
|
+
{ pattern: 'tail', message: 'tail はファイルのさいごの方をひょうじするコマンドだよ。さいしょの方を見るには、べつのコマンドをつかうよ。' },
|
|
795
|
+
],
|
|
671
796
|
},
|
|
672
797
|
{
|
|
673
798
|
id: 'obj-k1-07-02',
|
|
@@ -678,6 +803,10 @@ export const storyK1 = {
|
|
|
678
803
|
{ level: 2, text: '「tail」コマンドをつかうと、ファイルのさいごの方だけ見られるよ。' },
|
|
679
804
|
{ level: 3, text: '「tail 魔法の書.txt」とにゅうりょくしてね。' },
|
|
680
805
|
],
|
|
806
|
+
feedbacks: [
|
|
807
|
+
{ pattern: 'cat', message: 'cat はファイルのぜんぶをひょうじするよ。さいごの方だけ見るには、べつのコマンドをつかうよ。' },
|
|
808
|
+
{ pattern: 'head', message: 'head はファイルのさいしょの方をひょうじするコマンドだよ。さいごの方を見るには、べつのコマンドをつかうよ。' },
|
|
809
|
+
],
|
|
681
810
|
},
|
|
682
811
|
{
|
|
683
812
|
id: 'obj-k1-07-03',
|
|
@@ -691,6 +820,11 @@ export const storyK1 = {
|
|
|
691
820
|
{ level: 2, text: '「wc」コマンドをつかうと、行の数がわかるよ。' },
|
|
692
821
|
{ level: 3, text: '「wc 魔法の書.txt」とにゅうりょくしてね。' },
|
|
693
822
|
],
|
|
823
|
+
feedbacks: [
|
|
824
|
+
{ pattern: 'cat', message: 'cat はファイルの中身をひょうじするよ。行の数をかぞえるには、べつのコマンドをつかうよ。' },
|
|
825
|
+
{ pattern: 'head', message: 'head はファイルのさいしょの方をひょうじするよ。行数をかぞえるには、べつのコマンドをつかうよ。' },
|
|
826
|
+
{ pattern: 'tail', message: 'tail はファイルのさいごの方をひょうじするよ。行数をかぞえるには、べつのコマンドをつかうよ。' },
|
|
827
|
+
],
|
|
694
828
|
},
|
|
695
829
|
],
|
|
696
830
|
},
|
|
@@ -699,6 +833,13 @@ export const storyK1 = {
|
|
|
699
833
|
id: 'mission-k1-08',
|
|
700
834
|
title: '仲間リストを整理しよう',
|
|
701
835
|
description: '冒険者の名簿をきれいに整理しよう!',
|
|
836
|
+
goal: 'sort、uniq、cut をつかってデータを整理できるようになる',
|
|
837
|
+
review: {
|
|
838
|
+
question: 'おなじ行をまとめてくれるコマンドはどれかな?',
|
|
839
|
+
choices: ['sort', 'uniq', 'cut', 'grep'],
|
|
840
|
+
correctIndex: 1,
|
|
841
|
+
explanation: 'uniq はとなりあうおなじ行をまとめるコマンドだよ。sort でならべてから uniq をつかうと、ぜんぶのおなじ行をまとめられるよ。',
|
|
842
|
+
},
|
|
702
843
|
narrative: '古いお城で冒険者の名簿を見つけた。でも同じ名前が何回も書いてある。きれいに整理して、どんな職業の仲間がいるか調べよう。',
|
|
703
844
|
initialCwd: '/冒険の世界/古いお城',
|
|
704
845
|
initialFS: mission8FS,
|
|
@@ -713,6 +854,10 @@ export const storyK1 = {
|
|
|
713
854
|
{ level: 2, text: '「sort」コマンドで行をじゅんばんにできるよ。' },
|
|
714
855
|
{ level: 3, text: '「sort 冒険者名簿.csv」とにゅうりょくしてね。' },
|
|
715
856
|
],
|
|
857
|
+
feedbacks: [
|
|
858
|
+
{ pattern: 'cat', message: 'cat はファイルをそのままひょうじするよ。じゅんばんにならべるには、べつのコマンドをつかうよ。' },
|
|
859
|
+
{ pattern: 'uniq', message: 'uniq はおなじ行をまとめるコマンドだよ。まずはじゅんばんにならべるコマンドをつかおう。' },
|
|
860
|
+
],
|
|
716
861
|
},
|
|
717
862
|
{
|
|
718
863
|
id: 'obj-k1-08-02',
|
|
@@ -723,6 +868,10 @@ export const storyK1 = {
|
|
|
723
868
|
{ level: 2, text: '「sort」したあとに「|」で「uniq」につなげると、おなじ行をまとめられるよ。' },
|
|
724
869
|
{ level: 3, text: '「sort 冒険者名簿.csv | uniq」とにゅうりょくしてね。' },
|
|
725
870
|
],
|
|
871
|
+
feedbacks: [
|
|
872
|
+
{ pattern: 'grep', message: 'grep はことばをさがすコマンドだよ。おなじ行をまとめるには、べつのコマンドをつかうよ。' },
|
|
873
|
+
{ pattern: 'cat', message: 'cat はファイルをそのままひょうじするよ。おなじ行をまとめるには、sort と パイプ「|」をつかうよ。' },
|
|
874
|
+
],
|
|
726
875
|
},
|
|
727
876
|
{
|
|
728
877
|
id: 'obj-k1-08-03',
|
|
@@ -736,6 +885,10 @@ export const storyK1 = {
|
|
|
736
885
|
text: '「cut -d, -f2 冒険者名簿.csv」とにゅうりょくしてね。',
|
|
737
886
|
},
|
|
738
887
|
],
|
|
888
|
+
feedbacks: [
|
|
889
|
+
{ pattern: 'grep', message: 'grep はことばをさがすコマンドだよ。とくていの部分だけきりだすには、べつのコマンドをつかうよ。' },
|
|
890
|
+
{ pattern: 'cat', message: 'cat はファイルのぜんぶをひょうじするよ。とくていの部分だけきりだすには、べつのコマンドをつかうよ。' },
|
|
891
|
+
],
|
|
739
892
|
},
|
|
740
893
|
],
|
|
741
894
|
},
|
|
@@ -744,6 +897,13 @@ export const storyK1 = {
|
|
|
744
897
|
id: 'mission-k1-09',
|
|
745
898
|
title: '封印を解こう',
|
|
746
899
|
description: 'ふういんされた呪文をとけるようにして、魔法をつかおう!',
|
|
900
|
+
goal: 'chmod でけんげんをかえ、パイプで grep をつなげられるようになる',
|
|
901
|
+
review: {
|
|
902
|
+
question: 'ファイルのけんげん(つかえるかどうか)をかえるコマンドはどれかな?',
|
|
903
|
+
choices: ['chown', 'chmod', 'mv', 'cp'],
|
|
904
|
+
correctIndex: 1,
|
|
905
|
+
explanation: 'chmod はファイルのけんげん(パーミッション)をかえるコマンドだよ。「change mode」のりゃくだよ。',
|
|
906
|
+
},
|
|
747
907
|
narrative: '古いお城のおくで、ふういんされた呪文を見つけた!ふういんを解いて実行できるようにしよう。そして魔法の石から、つかいたい魔法をえらびだそう。',
|
|
748
908
|
initialCwd: '/冒険の世界/古いお城',
|
|
749
909
|
initialFS: mission9FS,
|
|
@@ -758,6 +918,10 @@ export const storyK1 = {
|
|
|
758
918
|
{ level: 2, text: '「chmod」コマンドで「+x」をつけると、実行できるようになるよ。' },
|
|
759
919
|
{ level: 3, text: '「chmod +x 封印の呪文.sh」とにゅうりょくしてね。' },
|
|
760
920
|
],
|
|
921
|
+
feedbacks: [
|
|
922
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。ふういんを解く(けんげんをかえる)には、べつのコマンドをつかうよ。' },
|
|
923
|
+
{ pattern: 'rm', message: 'rm はファイルをけすコマンドだよ。ふういんを解くには、けんげんをかえるコマンドをつかおう。' },
|
|
924
|
+
],
|
|
761
925
|
},
|
|
762
926
|
{
|
|
763
927
|
id: 'obj-k1-09-02',
|
|
@@ -768,6 +932,9 @@ export const storyK1 = {
|
|
|
768
932
|
{ level: 2, text: '「cat」でファイルを読んで、「|」で「grep」につなげると、ほしい行だけとりだせるよ。' },
|
|
769
933
|
{ level: 3, text: '「cat 魔法の石.txt | grep 光」とにゅうりょくしてね。' },
|
|
770
934
|
],
|
|
935
|
+
feedbacks: [
|
|
936
|
+
{ pattern: 'find', message: 'find はファイルの名前をさがすコマンドだよ。ファイルの中身からさがすには、grep をつかうよ。パイプ「|」でつなげてみよう。' },
|
|
937
|
+
],
|
|
771
938
|
},
|
|
772
939
|
],
|
|
773
940
|
},
|
|
@@ -776,6 +943,13 @@ export const storyK1 = {
|
|
|
776
943
|
id: 'mission-k1-10',
|
|
777
944
|
title: '冒険の記録をつけよう',
|
|
778
945
|
description: 'gitをつかって、冒険のきろくをかくにんしよう!',
|
|
946
|
+
goal: 'git status と git log で変更のきろくをかくにんできるようになる',
|
|
947
|
+
review: {
|
|
948
|
+
question: 'いままでのきろく(ログ)を見るgitコマンドはどれかな?',
|
|
949
|
+
choices: ['git status', 'git log', 'git add', 'git diff'],
|
|
950
|
+
correctIndex: 1,
|
|
951
|
+
explanation: 'git log はいままでのへんこうのきろく(コミット)をひょうじするコマンドだよ。git status はいまのじょうたいをたしかめるコマンドだよ。',
|
|
952
|
+
},
|
|
779
953
|
narrative: '秘密基地にもどってきた。冒険のきろくがgitでのこしてある。いままでの冒険をふりかえってみよう!',
|
|
780
954
|
initialCwd: '/冒険の世界/秘密基地',
|
|
781
955
|
initialFS: mission10FS,
|
|
@@ -793,6 +967,10 @@ export const storyK1 = {
|
|
|
793
967
|
{ level: 2, text: '「git status」でいまのじょうたいがわかるよ。' },
|
|
794
968
|
{ level: 3, text: '「git status」とにゅうりょくしてね。' },
|
|
795
969
|
],
|
|
970
|
+
feedbacks: [
|
|
971
|
+
{ pattern: 'ls', message: 'ls はフォルダの中身を見るコマンドだよ。gitのじょうたいを見るには、git のコマンドをつかうよ。' },
|
|
972
|
+
{ pattern: 'cat', message: 'cat はファイルを読むコマンドだよ。gitのじょうたいをかくにんするには、git のコマンドをつかうよ。' },
|
|
973
|
+
],
|
|
796
974
|
},
|
|
797
975
|
{
|
|
798
976
|
id: 'obj-k1-10-02',
|
|
@@ -806,6 +984,9 @@ export const storyK1 = {
|
|
|
806
984
|
{ level: 2, text: '「git log」でいままでのきろくが見られるよ。' },
|
|
807
985
|
{ level: 3, text: '「git log」とにゅうりょくしてね。' },
|
|
808
986
|
],
|
|
987
|
+
feedbacks: [
|
|
988
|
+
{ pattern: 'cat', message: 'cat はファイルの中身を読むコマンドだよ。gitのきろくを見るには、git のコマンドをつかうよ。' },
|
|
989
|
+
],
|
|
809
990
|
},
|
|
810
991
|
],
|
|
811
992
|
},
|
package/dist/data/types.d.ts
CHANGED
|
@@ -28,6 +28,16 @@ export interface Objective {
|
|
|
28
28
|
description: string;
|
|
29
29
|
checks: ObjectiveCheck[];
|
|
30
30
|
hints: Hint[];
|
|
31
|
+
feedbacks?: Array<{
|
|
32
|
+
pattern: string;
|
|
33
|
+
message: string;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export interface ReviewQuestion {
|
|
37
|
+
question: string;
|
|
38
|
+
choices: string[];
|
|
39
|
+
correctIndex: number;
|
|
40
|
+
explanation: string;
|
|
31
41
|
}
|
|
32
42
|
export interface FSNode {
|
|
33
43
|
type: 'file' | 'directory';
|
|
@@ -44,6 +54,8 @@ export interface Mission {
|
|
|
44
54
|
initialFS: FSNode;
|
|
45
55
|
initialCwd: string;
|
|
46
56
|
newCommands?: string[];
|
|
57
|
+
goal?: string;
|
|
58
|
+
review?: ReviewQuestion;
|
|
47
59
|
}
|
|
48
60
|
export interface Story {
|
|
49
61
|
id: string;
|
|
@@ -59,6 +71,7 @@ export interface StoryProgress {
|
|
|
59
71
|
completedMissions: string[];
|
|
60
72
|
currentMissionIndex: number;
|
|
61
73
|
hintsUsed: Record<string, number>;
|
|
74
|
+
commandsPerMission?: Record<string, number>;
|
|
62
75
|
}
|
|
63
76
|
export interface Achievement {
|
|
64
77
|
id: string;
|
|
@@ -89,6 +102,7 @@ export type Screen = {
|
|
|
89
102
|
type: 'missionComplete';
|
|
90
103
|
storyId: string;
|
|
91
104
|
missionIndex: number;
|
|
105
|
+
commandCount?: number;
|
|
92
106
|
} | {
|
|
93
107
|
type: 'progress';
|
|
94
108
|
} | {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Levenshtein distance-based command suggestion.
|
|
3
|
+
* Returns a suggestion string if a close match is found, otherwise null.
|
|
4
|
+
*/
|
|
5
|
+
export declare function suggestCommand(input: string): string | null;
|
|
6
|
+
/**
|
|
7
|
+
* Check mission-specific feedback patterns.
|
|
8
|
+
* Returns a feedback message if the input matches a pattern, otherwise null.
|
|
9
|
+
*/
|
|
10
|
+
export declare function checkMissionFeedback(input: string, feedbacks: Array<{
|
|
11
|
+
pattern: string;
|
|
12
|
+
message: string;
|
|
13
|
+
}>): string | null;
|
|
14
|
+
//# sourceMappingURL=CommandFeedback.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { commandRegistry } from './commands/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Levenshtein distance-based command suggestion.
|
|
4
|
+
* Returns a suggestion string if a close match is found, otherwise null.
|
|
5
|
+
*/
|
|
6
|
+
export function suggestCommand(input) {
|
|
7
|
+
const cmd = input.split(/\s+/)[0];
|
|
8
|
+
if (!cmd || commandRegistry[cmd])
|
|
9
|
+
return null;
|
|
10
|
+
const commands = Object.keys(commandRegistry);
|
|
11
|
+
let bestMatch = '';
|
|
12
|
+
let bestDistance = Infinity;
|
|
13
|
+
for (const known of commands) {
|
|
14
|
+
const dist = levenshtein(cmd, known);
|
|
15
|
+
if (dist < bestDistance) {
|
|
16
|
+
bestDistance = dist;
|
|
17
|
+
bestMatch = known;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Only suggest if distance is 2 or less (reasonable typo range)
|
|
21
|
+
if (bestDistance <= 2 && bestMatch) {
|
|
22
|
+
return bestMatch;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Check mission-specific feedback patterns.
|
|
28
|
+
* Returns a feedback message if the input matches a pattern, otherwise null.
|
|
29
|
+
*/
|
|
30
|
+
export function checkMissionFeedback(input, feedbacks) {
|
|
31
|
+
const cmd = input.split(/\s+/)[0];
|
|
32
|
+
for (const fb of feedbacks) {
|
|
33
|
+
if (cmd === fb.pattern || input.startsWith(fb.pattern)) {
|
|
34
|
+
return fb.message;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
function levenshtein(a, b) {
|
|
40
|
+
const m = a.length, n = b.length;
|
|
41
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
42
|
+
for (let i = 0; i <= m; i++)
|
|
43
|
+
dp[i][0] = i;
|
|
44
|
+
for (let j = 0; j <= n; j++)
|
|
45
|
+
dp[0][j] = j;
|
|
46
|
+
for (let i = 1; i <= m; i++) {
|
|
47
|
+
for (let j = 1; j <= n; j++) {
|
|
48
|
+
dp[i][j] = a[i - 1] === b[j - 1]
|
|
49
|
+
? dp[i - 1][j - 1]
|
|
50
|
+
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return dp[m][n];
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=CommandFeedback.js.map
|