@geekbeer/minion 3.36.0 → 3.40.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.
Files changed (39) hide show
  1. package/core/db/helpers.js +18 -0
  2. package/core/db/index.js +146 -0
  3. package/core/db/migrations/000_initial_schema.js +157 -0
  4. package/core/db/migrations/001_fts_trigram.js +78 -0
  5. package/core/db/migrations/002_emails_fts.js +41 -0
  6. package/core/db/migrations/003_memories_project_id.js +17 -0
  7. package/core/db/migrations/004_chat_sessions_workspace.js +18 -0
  8. package/core/db/migrations/005_todos_session_injection.js +19 -0
  9. package/core/db/migrations/006_daily_logs_workspace.js +69 -0
  10. package/core/db/migrations/007_workspace_scoping.js +29 -0
  11. package/core/db/migrations/008_todos_workspace.js +22 -0
  12. package/core/db/migrations/index.js +41 -0
  13. package/core/lib/config-warnings.js +16 -8
  14. package/core/lib/end-of-day.js +30 -14
  15. package/core/lib/reflection-scheduler.js +23 -9
  16. package/core/lib/thread-watcher.js +3 -0
  17. package/core/routes/daily-logs.js +64 -27
  18. package/core/routes/routines.js +6 -2
  19. package/core/routes/skills.js +4 -0
  20. package/core/routes/todos.js +20 -7
  21. package/core/routes/workflows.js +17 -7
  22. package/core/stores/daily-log-store.js +61 -30
  23. package/core/stores/execution-store.js +40 -18
  24. package/core/stores/routine-store.js +32 -14
  25. package/core/stores/todo-store.js +37 -10
  26. package/core/stores/workflow-store.js +34 -13
  27. package/docs/api-reference.md +66 -25
  28. package/linux/routes/chat.js +14 -9
  29. package/linux/routes/directives.js +4 -0
  30. package/linux/routine-runner.js +2 -0
  31. package/linux/workflow-runner.js +2 -0
  32. package/package.json +4 -2
  33. package/rules/core.md +1 -0
  34. package/scripts/new-migration.js +53 -0
  35. package/win/routes/chat.js +14 -9
  36. package/win/routes/directives.js +4 -0
  37. package/win/routine-runner.js +2 -0
  38. package/win/workflow-runner.js +2 -0
  39. package/core/db.js +0 -583
@@ -54,22 +54,40 @@ hq list workspaces
54
54
 
55
55
  ### Workflows
56
56
 
57
+ v3.38.0 以降、workflows はワークスペース単位でスコープされる。各workflowレコードは `workspace_id` を持ち、未指定は `""`(未所属/legacy)として扱われる。
58
+
57
59
  | Method | Endpoint | Description |
58
60
  |--------|----------|-------------|
59
- | GET | `/api/workflows` | List all local workflows with next_run |
60
- | POST | `/api/workflows` | Receive/upsert workflows (from HQ or local) |
61
+ | GET | `/api/workflows` | List local workflows with next_run. Optional `?workspace_id=` filter (omit for cross-workspace view) |
62
+ | POST | `/api/workflows` | Receive/upsert workflows (from HQ). Each incoming workflow should carry `workspace_id` |
61
63
  | POST | `/api/workflows/push/:name` | Push local workflow to HQ |
62
- | POST | `/api/workflows/fetch/:name` | Fetch workflow from HQ and deploy locally (+ pipeline skills) |
64
+ | POST | `/api/workflows/fetch/:name` | Fetch workflow from HQ and deploy locally (+ pipeline skills). HQ response includes `workspace_id` |
63
65
  | GET | `/api/workflows/remote` | List workflows on HQ |
64
66
  | DELETE | `/api/workflows/:id` | Remove a local workflow |
65
67
  | POST | `/api/workflows/trigger` | Manual trigger. Body: `{workflow_id}` |
66
68
 
69
+ ### Routines
70
+
71
+ v3.38.0 以降、routines はワークスペース単位でスコープされる。各routineレコードは `workspace_id` を持ち、未指定は `""`(未所属/legacy)として扱われる。
72
+
73
+ | Method | Endpoint | Description |
74
+ |--------|----------|-------------|
75
+ | GET | `/api/routines` | List local routines with next_run. Optional `?workspace_id=` filter (omit for cross-workspace view) |
76
+ | POST | `/api/routines` | Receive/upsert routines. Each incoming routine should carry `workspace_id` |
77
+ | POST | `/api/routines/sync` | Pull routines from HQ (HQ currently returns empty — routines are minion-local) |
78
+ | PUT | `/api/routines/:id/schedule` | Update cron/is_active |
79
+ | DELETE | `/api/routines/:id` | Remove a routine |
80
+ | POST | `/api/routines/bulk-toggle` | Set is_active for all routines |
81
+ | POST | `/api/routines/trigger` | Manual trigger. Body: `{routine_id}` or `{routine_name}` |
82
+
67
83
  ### Executions
68
84
 
85
+ v3.38.0 以降、executions は親 workflow / routine から `workspace_id` を継承する。
86
+
69
87
  | Method | Endpoint | Description |
70
88
  |--------|----------|-------------|
71
- | GET | `/api/executions` | List execution history (`?limit=50`, `?workflow_id=`) |
72
- | GET | `/api/executions/:id` | Get single execution |
89
+ | GET | `/api/executions` | List execution history (`?limit=50`, `?workflow_id=`, optional `?workspace_id=`) |
90
+ | GET | `/api/executions/:id` | Get single execution (includes `workspace_id`) |
73
91
  | GET | `/api/executions/:id/log` | Get execution log content (`?tail=N`) |
74
92
  | POST | `/api/executions/:id/outcome` | Report outcome (no auth). Body: `{outcome, summary?, details?}` |
75
93
 
@@ -176,22 +194,26 @@ Response (list):
176
194
 
177
195
  ### Daily Logs (Short-term Memory)
178
196
 
179
- Daily conversation summaries stored in SQLite (`$DATA_DIR/minion.db`).
180
- Generated via end-of-day processing or manual creation.
181
- Full-text search supported via FTS5.
197
+ Daily conversation summaries stored in SQLite (`$DATA_DIR/minion.db`), **scoped by workspace**.
198
+ One entry per `(workspace_id, date)` multiple workspaces can have distinct logs for the same day.
199
+ Generated via end-of-day processing or manual creation. Full-text search supported via FTS5.
200
+
201
+ All endpoints require a `workspace_id` identifying the scope. Pass an empty string `""` to address
202
+ legacy / unassigned logs created before workspace scoping (v3.37.0).
182
203
 
183
204
  | Method | Endpoint | Description |
184
205
  |--------|----------|-------------|
185
- | GET | `/api/daily-logs` | List all logs (date + size, newest first) |
186
- | GET | `/api/daily-logs?search=keyword` | Full-text search on log content (FTS5) |
187
- | POST | `/api/daily-logs` | Create a daily log. Body: `{date, content}` |
188
- | GET | `/api/daily-logs/:date` | Get a specific day's log content |
189
- | PUT | `/api/daily-logs/:date` | Update a daily log. Body: `{content}` |
190
- | DELETE | `/api/daily-logs/:date` | Delete a specific day's log |
206
+ | GET | `/api/daily-logs?workspace_id=<id>` | List logs for a workspace (date + size, newest first) |
207
+ | GET | `/api/daily-logs?workspace_id=<id>&search=keyword` | FTS5 search scoped to a workspace |
208
+ | POST | `/api/daily-logs` | Create a daily log. Body: `{workspace_id, date, content}` |
209
+ | GET | `/api/daily-logs/:date?workspace_id=<id>` | Get a specific day's log for a workspace |
210
+ | PUT | `/api/daily-logs/:date` | Update a daily log. Body: `{workspace_id, content}` |
211
+ | DELETE | `/api/daily-logs/:date?workspace_id=<id>` | Delete a specific day's log |
191
212
 
192
213
  POST body:
193
214
  ```json
194
215
  {
216
+ "workspace_id": "ws_abc123",
195
217
  "date": "2026-03-12",
196
218
  "content": "## 今日やったこと\n- Feature X を実装\n- Bug Y を修正"
197
219
  }
@@ -200,6 +222,7 @@ POST body:
200
222
  PUT body:
201
223
  ```json
202
224
  {
225
+ "workspace_id": "ws_abc123",
203
226
  "content": "## 今日やったこと\n- Feature X を実装(更新版)"
204
227
  }
205
228
  ```
@@ -219,16 +242,26 @@ Response (list):
219
242
 
220
243
  | Method | Endpoint | Description |
221
244
  |--------|----------|-------------|
222
- | POST | `/api/chat/end-of-day` | Generate daily log + extract memories from conversation |
245
+ | POST | `/api/chat/end-of-day` | Generate daily log for one workspace + extract memories from its conversation |
223
246
 
224
- Body: `{ "clear_session": false }` (optional, defaults to false)
247
+ Body:
248
+ ```json
249
+ {
250
+ "workspace_id": "ws_abc123",
251
+ "clear_session": false
252
+ }
253
+ ```
254
+
255
+ `workspace_id` is required. If no conversation exists for that workspace that day, a stub log
256
+ ("本日、このワークスペースでの会話はありませんでした。") is saved so idle days are still recorded.
225
257
 
226
258
  Response:
227
259
  ```json
228
260
  {
229
261
  "success": true,
230
262
  "daily_log": "2026-03-12",
231
- "memory_entries_added": 2
263
+ "memory_entries_added": 2,
264
+ "had_conversation": true
232
265
  }
233
266
  ```
234
267
 
@@ -255,16 +288,22 @@ curl -X PUT /api/config/env \
255
288
  The scheduler starts automatically on server boot if `REFLECTION_TIME` is configured.
256
289
  Changes via the config API take effect immediately (no restart required).
257
290
 
291
+ On each fire, the scheduler iterates all known workspaces (plus the `""` legacy bucket) and runs
292
+ end-of-day processing per workspace. Workspaces without conversation that day get a stub log so
293
+ the idle day is recorded.
294
+
258
295
  ### Todos
259
296
 
260
297
  ミニオンローカルのToDoリスト。SQLiteに永続化され、HQにも同期される。
261
298
 
299
+ v3.39.0 以降、todos はワークスペース単位でスコープされる。`POST /api/todos` 時に `workspace_id` が必須(未所属/legacy なら `""` を明示)。
300
+
262
301
  | Method | Endpoint | Description |
263
302
  |--------|----------|-------------|
264
- | GET | `/api/todos` | List todos. Query: `status`, `priority`, `project_id`, `source_type`, `session_id`, `limit` |
265
- | GET | `/api/todos/summary` | Status counts |
266
- | GET | `/api/todos/:id` | Get single todo |
267
- | POST | `/api/todos` | Create. Body: `{title, description?, priority?, source_type?, source_id?, project_id?, due_at?, session_id?, data?}` |
303
+ | GET | `/api/todos` | List todos. Query: `status`, `priority`, `project_id`, `source_type`, `session_id`, optional `workspace_id`, `limit` |
304
+ | GET | `/api/todos/summary` | Status counts. Optional `?workspace_id=` scopes the counts |
305
+ | GET | `/api/todos/:id` | Get single todo (includes `workspace_id`) |
306
+ | POST | `/api/todos` | Create. Body: `{title, workspace_id, description?, priority?, source_type?, source_id?, project_id?, due_at?, session_id?, data?}` — `workspace_id` is **required** |
268
307
  | PUT | `/api/todos/:id` | Update any field including `status` |
269
308
  | DELETE | `/api/todos/:id` | Delete |
270
309
 
@@ -276,10 +315,10 @@ Changes via the config API take effect immediately (no restart required).
276
315
 
277
316
  **セッション紐づけ例**:
278
317
  ```bash
279
- # 作成時にsession_idを指定すると、このセッションのチャットに自動で再掲される
318
+ # 作成時はworkspace_id必須(未所属/legacyなら"")。session_idを指定すると、このセッションのチャットに自動で再掲される
280
319
  curl -X POST -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" \
281
320
  http://localhost:8080/api/todos \
282
- -d '{"title": "レポートを保存", "session_id": "'$SESSION_ID'", "priority": "high"}'
321
+ -d '{"title": "レポートを保存", "workspace_id": "'$WORKSPACE_ID'", "session_id": "'$SESSION_ID'", "priority": "high"}'
283
322
 
284
323
  # 完了マーク(即座に更新すること)
285
324
  curl -X PUT -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" \
@@ -298,9 +337,11 @@ curl -X PUT -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/
298
337
 
299
338
  Allowed keys: `LLM_COMMAND`, `REFLECTION_TIME`
300
339
 
301
- ### LLM Plugins (opt-in)
340
+ ### LLM Plugins
341
+
342
+ プラグイン方式の LLM 設定。ワークフロー/ルーティン実行には `primary` の設定が必須。`primary` が未設定の場合、またはその名前が `enabled` に含まれていない場合はダッシュボードにエラーが表示される (heartbeat 経由)。設定は `~/minion/llm/config.json` にファイルとして保存される (env var に依存しないため quote 破損バグの影響を受けない)。
302
343
 
303
- プラグイン方式の LLM 設定。`primary` を設定すると有効化される。未設定の場合は従来の `LLM_COMMAND` 経路で動作する。設定は `~/minion/llm/config.json` にファイルとして保存される (env var に依存しないため quote 破損バグの影響を受けない)。
344
+ > **Note:** `LLM_COMMAND` 経路は obsolete。近々削除予定なので、新規ミニオンは必ず LLM プラグインを設定すること。
304
345
 
305
346
  | Method | Endpoint | Description |
306
347
  |--------|----------|-------------|
@@ -229,16 +229,21 @@ ${indexed}`
229
229
  return { success: true, carry_over: carryOver }
230
230
  })
231
231
 
232
- // POST /api/chat/end-of-day - Generate daily log + extract memories
232
+ // POST /api/chat/end-of-day - Generate daily log + extract memories for one workspace
233
233
  fastify.post('/api/chat/end-of-day', async (request, reply) => {
234
234
  if (!verifyToken(request)) {
235
235
  reply.code(401)
236
236
  return { success: false, error: 'Unauthorized' }
237
237
  }
238
238
 
239
- const { clear_session = false } = request.body || {}
239
+ const { workspace_id, clear_session = false } = request.body || {}
240
+ if (workspace_id !== '' && typeof workspace_id !== 'string') {
241
+ reply.code(400)
242
+ return { success: false, error: 'workspace_id is required' }
243
+ }
240
244
 
241
245
  const result = await runEndOfDay({
246
+ workspaceId: workspace_id,
242
247
  runQuickLlmCall,
243
248
  clearSession: clear_session,
244
249
  })
@@ -318,14 +323,14 @@ async function buildContextPrefix(message, context, sessionId, workspaceId) {
318
323
  '# メモリ詳細(IDを指定)',
319
324
  `curl -H "Authorization: Bearer $API_TOKEN" ${baseUrl}/api/memory/{id}`,
320
325
  '',
321
- '# デイリーログ検索',
322
- `curl -H "Authorization: Bearer $API_TOKEN" "${baseUrl}/api/daily-logs?search=キーワード"`,
326
+ '# デイリーログ検索(workspace_idは「現在のワークスペース」のIDを指定。未所属なら空文字)',
327
+ `curl -H "Authorization: Bearer $API_TOKEN" "${baseUrl}/api/daily-logs?workspace_id=現在のWSのID&search=キーワード"`,
323
328
  '',
324
- '# デイリーログ一覧',
325
- `curl -H "Authorization: Bearer $API_TOKEN" ${baseUrl}/api/daily-logs`,
329
+ '# デイリーログ一覧(現在のワークスペース)',
330
+ `curl -H "Authorization: Bearer $API_TOKEN" "${baseUrl}/api/daily-logs?workspace_id=現在のWSのID"`,
326
331
  '',
327
332
  '# 特定日のデイリーログ取得',
328
- `curl -H "Authorization: Bearer $API_TOKEN" ${baseUrl}/api/daily-logs/YYYY-MM-DD`,
333
+ `curl -H "Authorization: Bearer $API_TOKEN" "${baseUrl}/api/daily-logs/YYYY-MM-DD?workspace_id=現在のWSのID"`,
329
334
  '```',
330
335
  '',
331
336
  '参照すべきタイミング:',
@@ -366,10 +371,10 @@ async function buildContextPrefix(message, context, sessionId, workspaceId) {
366
371
  '',
367
372
  'ToDo APIの使い方:',
368
373
  '```bash',
369
- '# ToDo作成(session_idは後でセッションIDが判明してから設定)',
374
+ '# ToDo作成(workspace_idは必須。現在のワークスペースのIDを指定。未所属の場合は空文字 "")',
370
375
  `curl -X POST http://localhost:${port}/api/todos \\`,
371
376
  ' -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" \\',
372
- ' -d \'{"title": "ステップの説明", "session_id": "SESSION_ID", "priority": "normal"}\'',
377
+ ' -d \'{"title": "ステップの説明", "workspace_id": "現在のWSのID", "session_id": "SESSION_ID", "priority": "normal"}\'',
373
378
  '',
374
379
  '# ToDo完了',
375
380
  `curl -X PUT http://localhost:${port}/api/todos/{id} \\`,
@@ -87,6 +87,7 @@ async function directiveRoutes(fastify) {
87
87
  const startedAt = new Date().toISOString()
88
88
  const logFile = logManager.getLogPath(effectiveExecutionId)
89
89
  const workflowName = context?.workflow_name || skill_name
90
+ const workspaceId = context?.workspace_id || ''
90
91
 
91
92
  // Save initial execution record
92
93
  await executionStore.save({
@@ -94,6 +95,7 @@ async function directiveRoutes(fastify) {
94
95
  skill_name,
95
96
  workflow_id: null,
96
97
  workflow_name: workflowName,
98
+ workspace_id: workspaceId,
97
99
  status: 'running',
98
100
  outcome: null,
99
101
  started_at: startedAt,
@@ -117,6 +119,7 @@ async function directiveRoutes(fastify) {
117
119
  id: effectiveExecutionId,
118
120
  name: workflowName,
119
121
  pipeline_skill_names: [skill_name],
122
+ workspace_id: workspaceId,
120
123
  }, { skipExecutionReport: true })
121
124
 
122
125
  console.log(`[Directive] Execution completed: ${skill_name} (success: ${result.execution_id ? 'yes' : 'no'})`)
@@ -127,6 +130,7 @@ async function directiveRoutes(fastify) {
127
130
  skill_name,
128
131
  workflow_id: null,
129
132
  workflow_name: workflowName,
133
+ workspace_id: workspaceId,
130
134
  status: 'failed',
131
135
  outcome: 'failure',
132
136
  started_at: startedAt,
@@ -267,6 +267,7 @@ async function runRoutine(routine) {
267
267
  skill_name: pipelineSkillNames.join(' → '),
268
268
  routine_id: routine.id,
269
269
  routine_name: routine.name,
270
+ workspace_id: routine.workspace_id || '',
270
271
  status: 'running',
271
272
  outcome: null,
272
273
  started_at: startedAt,
@@ -287,6 +288,7 @@ async function runRoutine(routine) {
287
288
  skill_name: pipelineSkillNames.join(' → '),
288
289
  routine_id: routine.id,
289
290
  routine_name: routine.name,
291
+ workspace_id: routine.workspace_id || '',
290
292
  status: result.success ? 'completed' : 'failed',
291
293
  outcome: result.success ? null : 'failure',
292
294
  started_at: startedAt,
@@ -333,6 +333,7 @@ async function runWorkflow(workflow, options = {}) {
333
333
  skill_name: pipelineSkillNames.join(' → '),
334
334
  workflow_id: workflow.id,
335
335
  workflow_name: workflow.name,
336
+ workspace_id: workflow.workspace_id || '',
336
337
  status: 'running',
337
338
  outcome: null,
338
339
  started_at: startedAt,
@@ -355,6 +356,7 @@ async function runWorkflow(workflow, options = {}) {
355
356
  skill_name: pipelineSkillNames.join(' → '),
356
357
  workflow_id: workflow.id,
357
358
  workflow_name: workflow.name,
359
+ workspace_id: workflow.workspace_id || '',
358
360
  status: result.success ? 'completed' : 'failed',
359
361
  outcome,
360
362
  started_at: startedAt,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekbeer/minion",
3
- "version": "3.36.0",
3
+ "version": "3.40.1",
4
4
  "description": "AI Agent runtime for Minion - manages status and skill deployment on VPS",
5
5
  "main": "linux/server.js",
6
6
  "bin": {
@@ -19,12 +19,14 @@
19
19
  "roles/",
20
20
  "docs/",
21
21
  "settings/",
22
+ "scripts/",
22
23
  ".env.example"
23
24
  ],
24
25
  "scripts": {
25
26
  "start": "node linux/server.js",
26
27
  "start:win": "node win/server.js",
27
- "postinstall": "node postinstall.js"
28
+ "postinstall": "node postinstall.js",
29
+ "db:migration:new": "node scripts/new-migration.js"
28
30
  },
29
31
  "dependencies": {
30
32
  "croner": "^9.0.0",
package/rules/core.md CHANGED
@@ -218,6 +218,7 @@ Routine 実行中は以下もtmuxセッション環境で利用可能:
218
218
  - **Todoは「1往復で完了する粒度」に分解して登録する。** 大きいタスクは複数のTodoに分ける。粒度を小さく保てば、完了マークを圧縮に奪われにくい。
219
219
  - **完了したら即座に done にマークする。** まとめて更新しない。`PUT /api/todos/:id` で `status=done`。
220
220
  - **チャットセッション内で作成するTodoには必ず `session_id` を含める。** プロンプト冒頭の `[現在のチャットセッションID]` の値を使う。紐づいた未完了Todoは次ターン以降に自動で再掲される(圧縮を跨いでも失われない)。
221
+ - **`POST /api/todos` は `workspace_id` が必須(v3.39.0〜)。** プロンプト冒頭の `[現在のワークスペース]` のID値を使う。未所属の場合は空文字 `""` を明示的に渡す。workspace_id無しのリクエストは400エラーになる。
221
222
  - **再掲されたTodoを見たら、着手前に「既に完了していないか」を確認する。** 完了済みなら done に更新、未完なら続行。
222
223
  - 同一Todoが規定回数以上再掲されても未完了のままの場合、再掲は自動停止する。進展しないTodoはブロッカーとして起票するか手動で `cancelled` にすること。
223
224
 
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Scaffold a new DB migration file with a timestamp prefix.
4
+ *
5
+ * Usage: npm run db:migration:new <snake_case_name>
6
+ */
7
+
8
+ const fs = require('fs')
9
+ const path = require('path')
10
+
11
+ const name = process.argv[2]
12
+ if (!name) {
13
+ console.error('Usage: npm run db:migration:new <snake_case_name>')
14
+ process.exit(1)
15
+ }
16
+
17
+ if (!/^[a-z][a-z0-9_]*$/.test(name)) {
18
+ console.error(`Invalid name "${name}". Use snake_case (lowercase letters, digits, underscores).`)
19
+ process.exit(1)
20
+ }
21
+
22
+ const now = new Date()
23
+ const pad = n => String(n).padStart(2, '0')
24
+ const ts = `${now.getUTCFullYear()}${pad(now.getUTCMonth() + 1)}${pad(now.getUTCDate())}${pad(now.getUTCHours())}${pad(now.getUTCMinutes())}${pad(now.getUTCSeconds())}`
25
+ const version = Number(ts)
26
+ const filename = `${ts}_${name}.js`
27
+ const filepath = path.join(__dirname, '..', 'core', 'db', 'migrations', filename)
28
+
29
+ if (fs.existsSync(filepath)) {
30
+ console.error(`File already exists: ${filepath}`)
31
+ process.exit(1)
32
+ }
33
+
34
+ const template = `/**
35
+ * TODO: describe what this migration does and why.
36
+ */
37
+
38
+ module.exports = {
39
+ version: ${version},
40
+ name: '${name}',
41
+
42
+ up(db, { hasColumn, tableExists }) {
43
+ // Add an idempotent guard so re-runs (e.g., after a partial failure) are safe:
44
+ // if (hasColumn(db, 'some_table', 'some_column')) return
45
+ //
46
+ // Then apply the change:
47
+ // db.exec(\`ALTER TABLE some_table ADD COLUMN some_column TEXT\`)
48
+ },
49
+ }
50
+ `
51
+
52
+ fs.writeFileSync(filepath, template)
53
+ console.log(`Created ${path.relative(process.cwd(), filepath)}`)
@@ -299,16 +299,21 @@ ${indexed}`
299
299
  return { success: true, carry_over: carryOver }
300
300
  })
301
301
 
302
- // POST /api/chat/end-of-day - Generate daily log + extract memories
302
+ // POST /api/chat/end-of-day - Generate daily log + extract memories for one workspace
303
303
  fastify.post('/api/chat/end-of-day', async (request, reply) => {
304
304
  if (!verifyToken(request)) {
305
305
  reply.code(401)
306
306
  return { success: false, error: 'Unauthorized' }
307
307
  }
308
308
 
309
- const { clear_session = false } = request.body || {}
309
+ const { workspace_id, clear_session = false } = request.body || {}
310
+ if (workspace_id !== '' && typeof workspace_id !== 'string') {
311
+ reply.code(400)
312
+ return { success: false, error: 'workspace_id is required' }
313
+ }
310
314
 
311
315
  const result = await runEndOfDay({
316
+ workspaceId: workspace_id,
312
317
  runQuickLlmCall,
313
318
  clearSession: clear_session,
314
319
  })
@@ -381,14 +386,14 @@ async function buildContextPrefix(message, context, sessionId, workspaceId) {
381
386
  '# メモリ詳細(IDを指定)',
382
387
  `curl -H "Authorization: Bearer $API_TOKEN" ${baseUrl}/api/memory/{id}`,
383
388
  '',
384
- '# デイリーログ検索',
385
- `curl -H "Authorization: Bearer $API_TOKEN" "${baseUrl}/api/daily-logs?search=キーワード"`,
389
+ '# デイリーログ検索(workspace_idは「現在のワークスペース」のIDを指定。未所属なら空文字)',
390
+ `curl -H "Authorization: Bearer $API_TOKEN" "${baseUrl}/api/daily-logs?workspace_id=現在のWSのID&search=キーワード"`,
386
391
  '',
387
- '# デイリーログ一覧',
388
- `curl -H "Authorization: Bearer $API_TOKEN" ${baseUrl}/api/daily-logs`,
392
+ '# デイリーログ一覧(現在のワークスペース)',
393
+ `curl -H "Authorization: Bearer $API_TOKEN" "${baseUrl}/api/daily-logs?workspace_id=現在のWSのID"`,
389
394
  '',
390
395
  '# 特定日のデイリーログ取得',
391
- `curl -H "Authorization: Bearer $API_TOKEN" ${baseUrl}/api/daily-logs/YYYY-MM-DD`,
396
+ `curl -H "Authorization: Bearer $API_TOKEN" "${baseUrl}/api/daily-logs/YYYY-MM-DD?workspace_id=現在のWSのID"`,
392
397
  '```',
393
398
  '',
394
399
  '参照すべきタイミング:',
@@ -429,10 +434,10 @@ async function buildContextPrefix(message, context, sessionId, workspaceId) {
429
434
  '',
430
435
  'ToDo APIの使い方:',
431
436
  '```bash',
432
- '# ToDo作成(session_idは後でセッションIDが判明してから設定)',
437
+ '# ToDo作成(workspace_idは必須。現在のワークスペースのIDを指定。未所属の場合は空文字 "")',
433
438
  `curl -X POST http://localhost:${port}/api/todos \\`,
434
439
  ' -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" \\',
435
- ' -d \'{"title": "ステップの説明", "session_id": "SESSION_ID", "priority": "normal"}\'',
440
+ ' -d \'{"title": "ステップの説明", "workspace_id": "現在のWSのID", "session_id": "SESSION_ID", "priority": "normal"}\'',
436
441
  '',
437
442
  '# ToDo完了',
438
443
  `curl -X PUT http://localhost:${port}/api/todos/{id} \\`,
@@ -67,12 +67,14 @@ async function directiveRoutes(fastify) {
67
67
  const startedAt = new Date().toISOString()
68
68
  const logFile = logManager.getLogPath(effectiveExecutionId)
69
69
  const workflowName = context?.workflow_name || skill_name
70
+ const workspaceId = context?.workspace_id || ''
70
71
 
71
72
  await executionStore.save({
72
73
  id: effectiveExecutionId,
73
74
  skill_name,
74
75
  workflow_id: null,
75
76
  workflow_name: workflowName,
77
+ workspace_id: workspaceId,
76
78
  status: 'running',
77
79
  outcome: null,
78
80
  started_at: startedAt,
@@ -91,6 +93,7 @@ async function directiveRoutes(fastify) {
91
93
  id: effectiveExecutionId,
92
94
  name: workflowName,
93
95
  pipeline_skill_names: [skill_name],
96
+ workspace_id: workspaceId,
94
97
  }, { skipExecutionReport: true })
95
98
 
96
99
  console.log(`[Directive] Execution completed: ${skill_name} (success: ${result.execution_id ? 'yes' : 'no'})`)
@@ -101,6 +104,7 @@ async function directiveRoutes(fastify) {
101
104
  skill_name,
102
105
  workflow_id: null,
103
106
  workflow_name: workflowName,
107
+ workspace_id: workspaceId,
104
108
  status: 'failed',
105
109
  outcome: 'failure',
106
110
  started_at: startedAt,
@@ -208,6 +208,7 @@ async function runRoutine(routine) {
208
208
  skill_name: pipelineSkillNames.join(' -> '),
209
209
  routine_id: routine.id,
210
210
  routine_name: routine.name,
211
+ workspace_id: routine.workspace_id || '',
211
212
  status: 'running',
212
213
  outcome: null,
213
214
  started_at: startedAt,
@@ -225,6 +226,7 @@ async function runRoutine(routine) {
225
226
  skill_name: pipelineSkillNames.join(' -> '),
226
227
  routine_id: routine.id,
227
228
  routine_name: routine.name,
229
+ workspace_id: routine.workspace_id || '',
228
230
  status: result.success ? 'completed' : 'failed',
229
231
  outcome: result.success ? null : 'failure',
230
232
  started_at: startedAt,
@@ -303,6 +303,7 @@ async function runWorkflow(workflow, options = {}) {
303
303
  skill_name: pipelineSkillNames.join(' -> '),
304
304
  workflow_id: workflow.id,
305
305
  workflow_name: workflow.name,
306
+ workspace_id: workflow.workspace_id || '',
306
307
  status: 'running',
307
308
  outcome: null,
308
309
  started_at: startedAt,
@@ -322,6 +323,7 @@ async function runWorkflow(workflow, options = {}) {
322
323
  skill_name: pipelineSkillNames.join(' -> '),
323
324
  workflow_id: workflow.id,
324
325
  workflow_name: workflow.name,
326
+ workspace_id: workflow.workspace_id || '',
325
327
  status: result.success ? 'completed' : 'failed',
326
328
  outcome,
327
329
  started_at: startedAt,