@jcheesepkg/nanobot 0.8.99 → 0.9.1

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.
@@ -70,31 +70,31 @@ declare const ChannelsConfigSchema: z.ZodObject<{
70
70
  channelAccessToken?: string | undefined;
71
71
  }>>;
72
72
  }, "strip", z.ZodTypeAny, {
73
- telegram: {
74
- enabled: boolean;
75
- token: string;
76
- allowFrom: string[];
77
- proxy?: string | null | undefined;
78
- };
79
73
  line: {
80
74
  enabled: boolean;
81
75
  allowFrom: string[];
82
76
  channelSecret: string;
83
77
  channelAccessToken: string;
84
78
  };
85
- }, {
86
- telegram?: {
87
- enabled?: boolean | undefined;
88
- token?: string | undefined;
89
- allowFrom?: string[] | undefined;
79
+ telegram: {
80
+ enabled: boolean;
81
+ token: string;
82
+ allowFrom: string[];
90
83
  proxy?: string | null | undefined;
91
- } | undefined;
84
+ };
85
+ }, {
92
86
  line?: {
93
87
  enabled?: boolean | undefined;
94
88
  allowFrom?: string[] | undefined;
95
89
  channelSecret?: string | undefined;
96
90
  channelAccessToken?: string | undefined;
97
91
  } | undefined;
92
+ telegram?: {
93
+ enabled?: boolean | undefined;
94
+ token?: string | undefined;
95
+ allowFrom?: string[] | undefined;
96
+ proxy?: string | null | undefined;
97
+ } | undefined;
98
98
  }>;
99
99
  type ChannelsConfig = z.infer<typeof ChannelsConfigSchema>;
100
100
  declare const AgentDefaultsSchema: z.ZodObject<{
@@ -556,15 +556,15 @@ declare const ToolsConfigSchema: z.ZodObject<{
556
556
  export?: string | undefined;
557
557
  }>, "many">>;
558
558
  }, "strip", z.ZodTypeAny, {
559
+ exec: {
560
+ timeout: number;
561
+ };
559
562
  web: {
560
563
  search: {
561
564
  apiKey: string;
562
565
  maxResults: number;
563
566
  };
564
567
  };
565
- exec: {
566
- timeout: number;
567
- };
568
568
  restrictToWorkspace: boolean;
569
569
  enabled?: string[] | undefined;
570
570
  disabled?: string[] | undefined;
@@ -574,6 +574,9 @@ declare const ToolsConfigSchema: z.ZodObject<{
574
574
  export?: string | undefined;
575
575
  }[] | undefined;
576
576
  }, {
577
+ exec?: {
578
+ timeout?: number | undefined;
579
+ } | undefined;
577
580
  enabled?: string[] | undefined;
578
581
  web?: {
579
582
  search?: {
@@ -581,9 +584,6 @@ declare const ToolsConfigSchema: z.ZodObject<{
581
584
  maxResults?: number | undefined;
582
585
  } | undefined;
583
586
  } | undefined;
584
- exec?: {
585
- timeout?: number | undefined;
586
- } | undefined;
587
587
  restrictToWorkspace?: boolean | undefined;
588
588
  disabled?: string[] | undefined;
589
589
  custom?: {
@@ -675,31 +675,31 @@ declare const ConfigSchema: z.ZodObject<{
675
675
  channelAccessToken?: string | undefined;
676
676
  }>>;
677
677
  }, "strip", z.ZodTypeAny, {
678
- telegram: {
679
- enabled: boolean;
680
- token: string;
681
- allowFrom: string[];
682
- proxy?: string | null | undefined;
683
- };
684
678
  line: {
685
679
  enabled: boolean;
686
680
  allowFrom: string[];
687
681
  channelSecret: string;
688
682
  channelAccessToken: string;
689
683
  };
690
- }, {
691
- telegram?: {
692
- enabled?: boolean | undefined;
693
- token?: string | undefined;
694
- allowFrom?: string[] | undefined;
684
+ telegram: {
685
+ enabled: boolean;
686
+ token: string;
687
+ allowFrom: string[];
695
688
  proxy?: string | null | undefined;
696
- } | undefined;
689
+ };
690
+ }, {
697
691
  line?: {
698
692
  enabled?: boolean | undefined;
699
693
  allowFrom?: string[] | undefined;
700
694
  channelSecret?: string | undefined;
701
695
  channelAccessToken?: string | undefined;
702
696
  } | undefined;
697
+ telegram?: {
698
+ enabled?: boolean | undefined;
699
+ token?: string | undefined;
700
+ allowFrom?: string[] | undefined;
701
+ proxy?: string | null | undefined;
702
+ } | undefined;
703
703
  }>>;
704
704
  providers: z.ZodDefault<z.ZodObject<{
705
705
  anthropic: z.ZodDefault<z.ZodObject<{
@@ -1015,15 +1015,15 @@ declare const ConfigSchema: z.ZodObject<{
1015
1015
  export?: string | undefined;
1016
1016
  }>, "many">>;
1017
1017
  }, "strip", z.ZodTypeAny, {
1018
+ exec: {
1019
+ timeout: number;
1020
+ };
1018
1021
  web: {
1019
1022
  search: {
1020
1023
  apiKey: string;
1021
1024
  maxResults: number;
1022
1025
  };
1023
1026
  };
1024
- exec: {
1025
- timeout: number;
1026
- };
1027
1027
  restrictToWorkspace: boolean;
1028
1028
  enabled?: string[] | undefined;
1029
1029
  disabled?: string[] | undefined;
@@ -1033,6 +1033,9 @@ declare const ConfigSchema: z.ZodObject<{
1033
1033
  export?: string | undefined;
1034
1034
  }[] | undefined;
1035
1035
  }, {
1036
+ exec?: {
1037
+ timeout?: number | undefined;
1038
+ } | undefined;
1036
1039
  enabled?: string[] | undefined;
1037
1040
  web?: {
1038
1041
  search?: {
@@ -1040,9 +1043,6 @@ declare const ConfigSchema: z.ZodObject<{
1040
1043
  maxResults?: number | undefined;
1041
1044
  } | undefined;
1042
1045
  } | undefined;
1043
- exec?: {
1044
- timeout?: number | undefined;
1045
- } | undefined;
1046
1046
  restrictToWorkspace?: boolean | undefined;
1047
1047
  disabled?: string[] | undefined;
1048
1048
  custom?: {
@@ -1064,18 +1064,18 @@ declare const ConfigSchema: z.ZodObject<{
1064
1064
  };
1065
1065
  };
1066
1066
  channels: {
1067
- telegram: {
1068
- enabled: boolean;
1069
- token: string;
1070
- allowFrom: string[];
1071
- proxy?: string | null | undefined;
1072
- };
1073
1067
  line: {
1074
1068
  enabled: boolean;
1075
1069
  allowFrom: string[];
1076
1070
  channelSecret: string;
1077
1071
  channelAccessToken: string;
1078
1072
  };
1073
+ telegram: {
1074
+ enabled: boolean;
1075
+ token: string;
1076
+ allowFrom: string[];
1077
+ proxy?: string | null | undefined;
1078
+ };
1079
1079
  };
1080
1080
  providers: {
1081
1081
  anthropic: {
@@ -1139,15 +1139,15 @@ declare const ConfigSchema: z.ZodObject<{
1139
1139
  port: number;
1140
1140
  };
1141
1141
  tools: {
1142
+ exec: {
1143
+ timeout: number;
1144
+ };
1142
1145
  web: {
1143
1146
  search: {
1144
1147
  apiKey: string;
1145
1148
  maxResults: number;
1146
1149
  };
1147
1150
  };
1148
- exec: {
1149
- timeout: number;
1150
- };
1151
1151
  restrictToWorkspace: boolean;
1152
1152
  enabled?: string[] | undefined;
1153
1153
  disabled?: string[] | undefined;
@@ -1170,18 +1170,18 @@ declare const ConfigSchema: z.ZodObject<{
1170
1170
  } | undefined;
1171
1171
  } | undefined;
1172
1172
  channels?: {
1173
- telegram?: {
1174
- enabled?: boolean | undefined;
1175
- token?: string | undefined;
1176
- allowFrom?: string[] | undefined;
1177
- proxy?: string | null | undefined;
1178
- } | undefined;
1179
1173
  line?: {
1180
1174
  enabled?: boolean | undefined;
1181
1175
  allowFrom?: string[] | undefined;
1182
1176
  channelSecret?: string | undefined;
1183
1177
  channelAccessToken?: string | undefined;
1184
1178
  } | undefined;
1179
+ telegram?: {
1180
+ enabled?: boolean | undefined;
1181
+ token?: string | undefined;
1182
+ allowFrom?: string[] | undefined;
1183
+ proxy?: string | null | undefined;
1184
+ } | undefined;
1185
1185
  } | undefined;
1186
1186
  providers?: {
1187
1187
  anthropic?: {
@@ -1245,6 +1245,9 @@ declare const ConfigSchema: z.ZodObject<{
1245
1245
  port?: number | undefined;
1246
1246
  } | undefined;
1247
1247
  tools?: {
1248
+ exec?: {
1249
+ timeout?: number | undefined;
1250
+ } | undefined;
1248
1251
  enabled?: string[] | undefined;
1249
1252
  web?: {
1250
1253
  search?: {
@@ -1252,9 +1255,6 @@ declare const ConfigSchema: z.ZodObject<{
1252
1255
  maxResults?: number | undefined;
1253
1256
  } | undefined;
1254
1257
  } | undefined;
1255
- exec?: {
1256
- timeout?: number | undefined;
1257
- } | undefined;
1258
1258
  restrictToWorkspace?: boolean | undefined;
1259
1259
  disabled?: string[] | undefined;
1260
1260
  custom?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jcheesepkg/nanobot",
3
- "version": "0.8.99",
3
+ "version": "0.9.1",
4
4
  "description": "Lightweight AI assistant - TypeScript port",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: daily-summary
3
- description: Morning briefing with weather and schedule.
3
+ description: Automated morning briefing combining weather, schedule, and trash day. Use when user asks for 朝の要約 or wants a daily digest setup.
4
4
  ---
5
5
 
6
6
  # Daily Summary (朝の要約)
@@ -58,7 +58,7 @@ flex_message(template="morning_summary", data={
58
58
  })
59
59
  ```
60
60
 
61
- After the tool returns, output ONLY the raw JSON string returned by the tool. Do not wrap it in code blocks or add any other text. The JSON will be automatically rendered as a Flex Message card in LINE.
61
+ The card is sent automatically do NOT repeat the JSON. Just respond naturally after calling the tool.
62
62
 
63
63
  ## Personalization
64
64
 
@@ -73,4 +73,4 @@ Tomorrow's weather + clothing + morning events.
73
73
 
74
74
  ## Notes
75
75
 
76
- - ALWAYS use the `flex_message` tool — never output raw JSON directly
76
+ - ALWAYS use the `flex_message` tool — the card is auto-sent
@@ -1,18 +1,25 @@
1
1
  ---
2
2
  name: english
3
- description: Casual English conversation practice with corrections.
3
+ description: English conversation practice with level-based corrections, vocab tracking, and quizzes. Use when user says 英語, English mode, 英会話, 英語クイズ, or vocab test.
4
4
  ---
5
5
 
6
6
  # English Chat (英会話練習)
7
7
 
8
+ ## Data
9
+
10
+ All data in `data/english/`:
11
+ - `settings.json` — level preference
12
+ - `vocab.json` — accumulated vocabulary list
13
+ - `sessions.jsonl` — session logs (one JSON object per line)
14
+
8
15
  ## Difficulty Level
9
16
 
10
- Settings stored in `data/english.json`:
17
+ Settings stored in `data/english/settings.json`:
11
18
  ```json
12
19
  { "level": "beginner" }
13
20
  ```
14
21
 
15
- On first activation, if `data/english.json` doesn't exist, ask the user to choose their level:
22
+ On first activation, if `data/english/settings.json` doesn't exist, ask the user to choose their level:
16
23
  ```
17
24
  flex_message(template="action_buttons", data={
18
25
  prompt: "英語レベルを選んでね!\nChoose your English level:",
@@ -24,7 +31,7 @@ flex_message(template="action_buttons", data={
24
31
  })
25
32
  ```
26
33
 
27
- Save the choice to `data/english.json`. User can change anytime with "レベル変更".
34
+ Save the choice to `data/english/settings.json`. User can change anytime with "レベル変更".
28
35
 
29
36
  ### Level behavior
30
37
 
@@ -39,7 +46,7 @@ Save the choice to `data/english.json`. User can change anytime with "レベル
39
46
 
40
47
  When user says "英語モード" / "English mode" / "英会話":
41
48
 
42
- 1. Read `data/english.json` for level (default: beginner if missing)
49
+ 1. Read `data/english/settings.json` for level (default: beginner if missing)
43
50
  2. Reply in English, adapted to level
44
51
  3. Gently correct mistakes (strictness based on level)
45
52
  4. Offer Japanese translation based on level rules above
@@ -106,12 +113,26 @@ When user says "日本語に戻して" / "exit English" / "おわり":
106
113
  - Corrections you made (original → fixed)
107
114
  - New vocabulary or phrases you introduced
108
115
  - An encouraging comment about their performance
109
- 2. Send a session summary using `flex_message`:
110
116
 
117
+ 2. **Save session log** — append one JSON line to `data/english/sessions.jsonl`:
118
+ ```bash
119
+ echo '{"date":"2025-02-13","topics":["daily life","food"],"corrections":[{"wrong":"I go","right":"I went","rule":"past tense"}],"vocab":["commute","grab a bite"],"duration_msgs":12}' >> data/english/sessions.jsonl
120
+ ```
121
+
122
+ 3. **Update vocab list** — read `data/english/vocab.json`, merge new words, write back:
123
+ ```json
124
+ [
125
+ { "word": "commute", "meaning": "通勤する", "date": "2025-02-13" },
126
+ { "word": "grab a bite", "meaning": "軽く食べる", "date": "2025-02-13" }
127
+ ]
128
+ ```
129
+ If the file doesn't exist, create it with the new entries. Skip duplicates (same `word`).
130
+
131
+ 4. **Send session summary card**:
111
132
  ```
112
133
  flex_message(template="custom", data={
113
134
  title: "📝 English Session",
114
- body: "Topics: ...\n\nCorrections:\n❌ I go → ✅ I went\n❌ more easy → ✅ easier\n\nNew vocab:\n• commute (通勤する)\n• grab a bite (軽く食べる)\n\n💪 Great job! Your past tense is improving!",
135
+ body: "Topics: daily life, food\n\nCorrections:\n❌ I go → ✅ I went\n❌ more easy → ✅ easier\n\nNew vocab:\n• commute (通勤する)\n• grab a bite (軽く食べる)\n\n💪 Great job! Your past tense is improving!",
115
136
  header_color: "#4CAF50"
116
137
  })
117
138
  ```
@@ -120,6 +141,29 @@ Keep it honest — if there were no corrections, say so. If there were many, pic
120
141
 
121
142
  After the card, respond: "英語練習お疲れ様!👍"
122
143
 
144
+ ## Vocab Review
145
+
146
+ When user says "英語クイズ" / "vocab test" / "復習":
147
+
148
+ 1. Read `data/english/vocab.json`
149
+ 2. Pick 5 random words from past sessions
150
+ 3. Quiz the user — show the English word, ask for meaning or usage in a sentence
151
+ 4. Use `action_buttons` for multiple choice if beginner level
152
+
153
+ Example:
154
+ ```
155
+ flex_message(template="action_buttons", data={
156
+ prompt: "What does 'commute' mean?",
157
+ buttons: [
158
+ { label: "通勤する", text: "答え 通勤する", style: "primary" },
159
+ { label: "通信する", text: "答え 通信する", style: "secondary" },
160
+ { label: "通過する", text: "答え 通過する", style: "secondary" }
161
+ ]
162
+ })
163
+ ```
164
+
165
+ For intermediate/advanced: just ask in text, no multiple choice.
166
+
123
167
  ## Tips
124
168
 
125
169
  - Match user's level
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: expense
3
- description: Track daily expenses and show monthly summaries.
3
+ description: Expense tracker with auto-categorization and monthly receipt summaries. Use when user mentions spending like 出費, 500円, or asks for expense reports.
4
4
  ---
5
5
 
6
6
  # Expense Tracker (出費記録)
@@ -11,7 +11,7 @@ User says: "コンビニで500円" / "出費 +380 カフェ" / "ランチ 1200"
11
11
 
12
12
  Log to CSV:
13
13
  ```bash
14
- echo "$(date +%Y-%m-%d),$(date +%H:%M),500,コンビニ,コンビニ" >> data/expenses.csv
14
+ echo "$(date +%Y-%m-%d),$(date +%H:%M),500,コンビニ,コンビニ" >> data/expense/log.csv
15
15
  ```
16
16
 
17
17
  Format: `date,time,amount,note,category`
@@ -30,38 +30,37 @@ Default: 雑費
30
30
 
31
31
  ## Confirmation
32
32
 
33
- Simple text:
34
- ```
35
- ✅ 記録: カフェ ¥380
36
- 今月: ¥12,340
37
- ```
33
+ After recording, confirm with a short text: "✅ 記録: カフェ ¥380"
38
34
 
39
35
  ## Summary
40
36
 
41
- Monthly:
37
+ Monthly totals:
42
38
  ```bash
43
- awk -F, '$1 ~ /^2025-02/ {sum+=$3} END {print sum}' data/expenses.csv
39
+ awk -F, '$1 ~ /^2025-02/ {sum+=$3} END {print sum}' data/expense/log.csv
44
40
  ```
45
41
 
46
42
  By category:
47
43
  ```bash
48
- awk -F, '$1 ~ /^2025-02/ {cat[$5]+=$3} END {for(c in cat) print c, cat[c]}' data/expenses.csv
44
+ awk -F, '$1 ~ /^2025-02/ {cat[$5]+=$3} END {for(c in cat) print c, cat[c]}' data/expense/log.csv
49
45
  ```
50
46
 
51
- Text summary:
52
- ```
53
- 📊 2月の出費
47
+ **ALWAYS use `flex_message`** for summaries. The card is auto-sent.
54
48
 
55
- 合計: ¥45,230
56
-
57
- 内訳:
58
- 食事 ¥18,500
59
- カフェ ¥6,200
60
- 交通 ¥8,400
61
- その他 ¥12,130
49
+ Monthly summary as receipt card:
50
+ ```
51
+ flex_message(template="receipt", data={
52
+ title: "2月の出費",
53
+ items: [
54
+ { name: "食事", value: "¥18,500" },
55
+ { name: "カフェ", value: "¥6,200" },
56
+ { name: "交通", value: "¥8,400" },
57
+ { name: "その他", value: "¥12,130" }
58
+ ],
59
+ total: "¥45,230"
60
+ })
62
61
  ```
63
62
 
64
63
  ## Commands
65
64
 
66
- - "出費" / "今月の出費" → summary
65
+ - "出費" / "今月の出費" → monthly receipt card
67
66
  - "出費 詳細" → recent entries
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: fortune
3
- description: Daily horoscope readings.
3
+ description: Daily horoscope and zodiac readings. Use when user says 占い, 運勢, 星座, or asks about their fortune/horoscope.
4
4
  ---
5
5
 
6
6
  # Fortune (占い)
@@ -55,7 +55,7 @@ flex_message(template="fortune", data={
55
55
  })
56
56
  ```
57
57
 
58
- After the tool returns, output ONLY the raw JSON string returned by the tool. Do not wrap it in code blocks or add any other text. The JSON will be automatically rendered as a Flex Message card in LINE.
58
+ The card is sent automatically do NOT repeat the JSON. Just respond naturally after calling the tool.
59
59
 
60
60
  ## Commands
61
61
 
@@ -87,4 +87,4 @@ Match bot tone:
87
87
 
88
88
  - Same sign = same fortune all day (deterministic)
89
89
  - Keep it fun, not serious
90
- - ALWAYS use the `flex_message` tool — never output raw JSON directly
90
+ - ALWAYS use the `flex_message` tool — the card is auto-sent
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: habit
3
- description: Track daily habits with streaks.
3
+ description: Habit tracker with streak counting and weekly summaries. Use when user says 習慣, mentions completing a habit, or wants to add/check habits.
4
4
  ---
5
5
 
6
6
  # Habit Tracker (習慣トラッカー)
7
7
 
8
8
  ## Setup
9
9
 
10
- Store habits in `data/habits.json`:
10
+ Store habits in `data/habit/config.json`:
11
11
  ```json
12
12
  {
13
13
  "habits": [
@@ -20,40 +20,56 @@ Store habits in `data/habits.json`:
20
20
 
21
21
  ## Daily Check-in
22
22
 
23
- Simple text with quick_replies:
24
- ```
25
- 📋 今日の習慣
26
- 🧘 瞑想 ✓
27
- 🏃 運動
28
- 📖 読書 ✓
23
+ **ALWAYS use `flex_message`** for daily check-in. Use carousel with one card per habit:
29
24
 
30
- [[quick_replies: 🧘 瞑想やった, 🏃 運動やった, 📖 読書やった]]
31
25
  ```
26
+ flex_message(template="custom", data={
27
+ bubbles: [
28
+ {
29
+ type: "bubble",
30
+ header: { type: "box", layout: "vertical", backgroundColor: "#4CAF50", contents: [{ type: "text", text: "🧘 瞑想", color: "#FFFFFF", weight: "bold" }] },
31
+ body: { type: "box", layout: "vertical", contents: [{ type: "text", text: "🔥 7日連続!", wrap: true }] },
32
+ footer: { type: "box", layout: "vertical", contents: [{ type: "button", action: { type: "message", label: "✅ やった!", text: "瞑想やった" }, style: "primary", color: "#4CAF50" }] }
33
+ },
34
+ {
35
+ type: "bubble",
36
+ header: { type: "box", layout: "vertical", backgroundColor: "#FF9800", contents: [{ type: "text", text: "🏃 運動", color: "#FFFFFF", weight: "bold" }] },
37
+ body: { type: "box", layout: "vertical", contents: [{ type: "text", text: "まだやってないよ〜", wrap: true }] },
38
+ footer: { type: "box", layout: "vertical", contents: [{ type: "button", action: { type: "message", label: "✅ やった!", text: "運動やった" }, style: "primary", color: "#FF9800" }] }
39
+ }
40
+ ]
41
+ })
42
+ ```
43
+
44
+ The card is auto-sent — do NOT repeat the JSON.
45
+
46
+ - Green header (#4CAF50) = already done today
47
+ - Orange header (#FF9800) = not done yet
48
+ - Read `data/habit/log.csv` to check today's status before building the carousel
32
49
 
33
50
  ## Logging
34
51
 
35
52
  ```bash
36
- echo "$(date +%Y-%m-%d)|meditate|1" >> data/habit-log.csv
53
+ echo "$(date +%Y-%m-%d)|meditate|1" >> data/habit/log.csv
37
54
  ```
38
55
 
39
56
  ## Streaks
40
57
 
41
58
  ```bash
42
59
  # Count consecutive days
43
- awk -F"|" '$2=="meditate" && $3=="1" {print $1}' data/habit-log.csv | uniq | tail -7 | wc -l
60
+ awk -F"|" '$2=="meditate" && $3=="1" {print $1}' data/habit/log.csv | uniq | tail -7 | wc -l
44
61
  ```
45
62
 
46
63
  ## Summary
47
64
 
48
- Text-based weekly:
49
- ```
50
- 📊 今週の習慣
51
-
52
- 🧘 瞑想: 7/7 🔥7日連続!
53
- 🏃 運動: 5/7
54
- 📖 読書: 3/7
65
+ **ALWAYS use `flex_message`** for weekly summaries. The card is auto-sent.
55
66
 
56
- すごい!瞑想毎日達成!✨
67
+ ```
68
+ flex_message(template="custom", data={
69
+ title: "📊 今週の習慣",
70
+ body: "🧘 瞑想: 7/7 🔥7日連続!\n🏃 運動: 5/7\n📖 読書: 3/7\n\nすごい!瞑想毎日達成!✨",
71
+ header_color: "#4CAF50"
72
+ })
57
73
  ```
58
74
 
59
75
  ## Commands
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: hydration
3
- description: Track daily water intake with reminders.
3
+ description: Water intake tracker with reminders and progress display. Use when user says 水飲んだ, 一杯, or asks about hydration.
4
4
  ---
5
5
 
6
6
  # Hydration Tracker (水分摂取)
@@ -11,13 +11,13 @@ User says: "水飲んだ" / "一杯飲んだ" / "+1"
11
11
 
12
12
  Log:
13
13
  ```bash
14
- echo "$(date -Iseconds)|1" >> data/hydration.log
14
+ echo "$(date -Iseconds)|1" >> data/hydration/log.csv
15
15
  ```
16
16
 
17
17
  ## Check Progress
18
18
 
19
19
  ```bash
20
- grep "$(date +%Y-%m-%d)" data/hydration.log | wc -l
20
+ grep "$(date +%Y-%m-%d)" data/hydration/log.csv | wc -l
21
21
  ```
22
22
 
23
23
  ## Output
@@ -36,7 +36,7 @@ flex_message(template="hydration", data={
36
36
  })
37
37
  ```
38
38
 
39
- After the tool returns, output ONLY the raw JSON string returned by the tool. Do not wrap it in code blocks or add any other text. The JSON will be automatically rendered as a Flex Message card in LINE.
39
+ The card is sent automatically do NOT repeat the JSON. Just respond naturally after calling the tool.
40
40
 
41
41
  ## Setup Reminder
42
42
 
@@ -48,10 +48,10 @@ cron(action="add", message="水飲んだ?リマインド送って", every_seco
48
48
 
49
49
  Archive at midnight:
50
50
  ```bash
51
- [ -f data/hydration.log ] && mv data/hydration.log data/hydration-$(date +%Y-%m-%d).log
51
+ [ -f data/hydration/log.csv ] && mv data/hydration/log.csv data/hydration/log-$(date +%Y-%m-%d).csv
52
52
  ```
53
53
 
54
54
  ## Notes
55
55
 
56
- - ALWAYS use the `flex_message` tool — never output raw JSON directly
57
- - Update `current` count by reading from `data/hydration.log` before calling the tool
56
+ - ALWAYS use the `flex_message` tool — the card is auto-sent
57
+ - Update `current` count by reading from `data/hydration/log.csv` before calling the tool
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mood
3
- description: Daily mood tracking with emoji and optional notes.
3
+ description: Mood journal with emoji tracking and weekly reports. Use when user shares feelings like 気分, だるい, 疲れた, いい感じ, or asks for mood summary.
4
4
  ---
5
5
 
6
6
  # Mood Journal (気分日記)
@@ -20,39 +20,46 @@ Map to emoji + score:
20
20
 
21
21
  Log to CSV:
22
22
  ```bash
23
- echo "$(date +%Y-%m-%d),$(date +%H:%M),😊,5,今日はいい感じ" >> data/mood.csv
23
+ echo "$(date +%Y-%m-%d),$(date +%H:%M),😊,5,今日はいい感じ" >> data/mood/log.csv
24
24
  ```
25
25
 
26
26
  Format: `date,time,emoji,score,note`
27
27
 
28
28
  ## Daily Check-in
29
29
 
30
- Use quick_replies directive for simple tap response:
30
+ Use `action_buttons` flex for tap response:
31
31
  ```
32
- 今日の気分は?
33
-
34
- [[quick_replies: 😊 いい, 😐 普通, 😔 だるい, 😢 辛い]]
32
+ flex_message(template="action_buttons", data={
33
+ prompt: "今日の気分は?",
34
+ buttons: [
35
+ { label: "😊 いい", text: "気分 😊 いい", style: "primary" },
36
+ { label: "😐 普通", text: "気分 😐 普通", style: "secondary" },
37
+ { label: "😔 だるい", text: "気分 😔 だるい", style: "secondary" },
38
+ { label: "😢 辛い", text: "気分 😢 辛い", style: "secondary" }
39
+ ]
40
+ })
35
41
  ```
36
42
 
37
- Set up cron:
43
+ The card is auto-sent. Set up cron for nightly check-in:
38
44
  ```
39
- cron(action="add", message="今日の気分は?\n\n[[quick_replies: 😊 いい, 😐 普通, 😔 だるい]]", cron_expr="0 21 * * *", timezone="Asia/Tokyo")
45
+ cron(action="add", message="気分チェックインのカードを送って", cron_expr="0 21 * * *", timezone="Asia/Tokyo", kind="task")
40
46
  ```
41
47
 
42
48
  ## Summary
43
49
 
44
50
  Calculate average:
45
51
  ```bash
46
- awk -F, 'NR>7 {sum+=$4; count++} END {print "avg:", sum/count}' data/mood.csv
52
+ awk -F, 'NR>7 {sum+=$4; count++} END {print "avg:", sum/count}' data/mood/log.csv
47
53
  ```
48
54
 
49
- Weekly text summary:
50
- ```
51
- 📊 今週の気分
52
- 平均: 3.8 / 5
53
- 😊😊😐😊😔😊😊
55
+ **ALWAYS use `flex_message`** for weekly summaries. The card is auto-sent.
54
56
 
55
- 一番多かったのは 😊 です!
57
+ ```
58
+ flex_message(template="custom", data={
59
+ title: "📊 今週の気分",
60
+ body: "😊😊😐😊😔😊😊\n\n平均: 3.8 / 5\n一番多かったのは 😊 です!\n\nいい調子!来週もこの感じで👍",
61
+ header_color: "#FF9800"
62
+ })
56
63
  ```
57
64
 
58
65
  ## Notes
@@ -36,6 +36,7 @@ skill-name/
36
36
  scripts/ (optional) - Executable code
37
37
  references/ (optional) - Documentation for context
38
38
  assets/ (optional) - Files used in output
39
+ data/ (optional) - User data, settings, logs
39
40
  ```
40
41
 
41
42
  #### SKILL.md
@@ -72,6 +73,24 @@ Skills use three-level loading:
72
73
  - `description`: What the skill does AND when to use it. Include trigger contexts.
73
74
  All "when to use" info goes here since the body only loads after triggering.
74
75
 
76
+ ### Data Storage
77
+
78
+ **Custom skills** live in the workspace `skills/` directory. Store user data in `data/` within the skill, using the **full path from workspace root** in SKILL.md:
79
+
80
+ ```
81
+ skills/my-skill/
82
+ SKILL.md
83
+ data/
84
+ log.csv
85
+ settings.json
86
+ ```
87
+
88
+ ```bash
89
+ echo "..." >> skills/my-skill/data/log.csv
90
+ ```
91
+
92
+ NOT `data/log.csv` — that would write to the workspace root.
93
+
75
94
  ### Flex Message Integration
76
95
 
77
96
  If the skill produces output that would benefit from rich visual display (cards, progress trackers, summaries, confirmations), include `flex_message` tool usage in the SKILL.md.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: weather
3
- description: Get current weather and forecasts (no API key required).
3
+ description: Weather forecasts and clothing advice. Use when user asks about 天気, 気温, 服装, or weather in any city.
4
4
  ---
5
5
 
6
6
  # Weather
@@ -81,6 +81,23 @@ Additional:
81
81
 
82
82
  ---
83
83
 
84
+ ## Output
85
+
86
+ **ALWAYS use `flex_message`** to display weather results. The card is auto-sent.
87
+
88
+ Color the header based on conditions:
89
+ - 晴れ: `#1DB446` (green)
90
+ - 曇り: `#607D8B` (grey)
91
+ - 雨/雪: `#2196F3` (blue)
92
+
93
+ ```
94
+ flex_message(template="custom", data={
95
+ title: "🌤 東京の天気",
96
+ body: "現在: 12°C (体感10°C)\n曇り\n\n朝 6時: 8°C\n昼12時: 14°C\n晩18時: 11°C\n\n👔 ジャケット or カーディガン",
97
+ header_color: "#607D8B"
98
+ })
99
+ ```
100
+
84
101
  ## Full Forecast (no jq)
85
102
 
86
103
  ```bash