@geekbeer/minion 3.27.1 → 3.29.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.
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  const stepPoller = require('../lib/step-poller')
11
+ const dagStepPoller = require('../lib/dag-step-poller')
11
12
  const revisionWatcher = require('../lib/revision-watcher')
12
13
  const threadWatcher = require('../lib/thread-watcher')
13
14
  const reflectionScheduler = require('../lib/reflection-scheduler')
@@ -22,6 +23,7 @@ async function daemonRoutes(fastify, opts) {
22
23
  success: true,
23
24
  daemons: {
24
25
  step_poller: stepPoller.getStatus(),
26
+ dag_step_poller: dagStepPoller.getStatus(),
25
27
  revision_watcher: revisionWatcher.getStatus(),
26
28
  thread_watcher: threadWatcher.getStatus(),
27
29
  reflection_scheduler: reflectionScheduler.getStatus(),
@@ -1012,6 +1012,7 @@ DAG ワークフローは従来の線形パイプラインを拡張した有向
1012
1012
 
1013
1013
  | Method | Endpoint | Description |
1014
1014
  |--------|----------|-------------|
1015
+ | GET | `/api/minion/dag-workflows` | ミニオンがアクセス可能な DAG ワークフロー一覧を取得 |
1015
1016
  | POST | `/api/minion/dag-workflows` | 新規 DAG ワークフローを作成(ドラフトとして保存) |
1016
1017
  | PUT | `/api/minion/dag-workflows/:id` | ドラフト graph / メタデータを更新 |
1017
1018
  | POST | `/api/minion/dag-workflows/:id/publish` | ドラフトをバリデーションし新バージョンとして公開 |
@@ -1055,16 +1056,216 @@ POST `/api/minion/dag-workflows/:id/publish` (body なし):
1055
1056
  - OK なら新バージョン行を `dag_workflow_versions` に追加し、`current_version_id` を更新、ドラフトをクリア
1056
1057
  - NG なら 400 で `{ error, details: [...] }` を返却
1057
1058
 
1059
+ ### ノード/エッジ操作エンドポイント (PMロール限定)
1060
+
1061
+ **graph 全文を JSON で書く代わりに、ノード・エッジを1つずつ操作する**ためのAPI。各操作は自動でドラフトに保存され、レスポンスに `validation` フィールド(`validateDagGraph` によるフル検証結果)を含む。これにより、1操作ごとにバリデーションフィードバックを受け取れる。
1062
+
1063
+ | Method | Endpoint | Description |
1064
+ |--------|----------|-------------|
1065
+ | POST | `/api/minion/dag-workflows/:id/nodes` | ノードを追加(エッジ自動生成対応) |
1066
+ | PATCH | `/api/minion/dag-workflows/:id/nodes/:nodeId` | ノードのプロパティを更新 |
1067
+ | DELETE | `/api/minion/dag-workflows/:id/nodes/:nodeId` | ノードを削除(自動再接続対応) |
1068
+ | POST | `/api/minion/dag-workflows/:id/edges` | エッジを追加 |
1069
+ | PATCH | `/api/minion/dag-workflows/:id/edges/:edgeId` | エッジの kind / condition_label を更新 |
1070
+ | DELETE | `/api/minion/dag-workflows/:id/edges/:edgeId` | エッジを削除 |
1071
+ | POST | `/api/minion/dag-workflows/:id/validate` | ドラフトをフル検証(公開せず) |
1072
+
1073
+ #### POST `/api/minion/dag-workflows/:id/nodes` — ノード追加
1074
+
1075
+ ```json
1076
+ {
1077
+ "type": "skill",
1078
+ "label": "Fetch Data",
1079
+ "after": "start",
1080
+ "before": "end",
1081
+ "skill_id": "<skill-uuid>",
1082
+ "skill_version_id": "<version-uuid>",
1083
+ "assigned_role": "engineer"
1084
+ }
1085
+ ```
1086
+
1087
+ - `type` (必須): `start` | `end` | `skill` | `review` | `fan_out` | `join` | `conditional` | `transform`
1088
+ - `id` (任意): 省略時は `<type>_1`, `<type>_2`, ... で自動採番
1089
+ - `label` (任意): 省略時は `New <type>`
1090
+ - `after` (任意): このノードの後ろに挿入。`after` → 新ノード へのエッジを自動生成
1091
+ - `before` (任意): このノードの前に挿入。新ノード → `before` へのエッジを自動生成
1092
+ - `after` と `before` を**両方指定**すると、既存の `after → before` エッジを削除して `after → 新ノード → before` に差し替え
1093
+
1094
+ **ノードタイプ別の必須フィールド(publish 時検証):**
1095
+
1096
+ | type | 必須フィールド | 備考 |
1097
+ |------|---------------|------|
1098
+ | `start` / `end` | なし | |
1099
+ | `skill` | `skill_id`, `skill_version_id`, `assigned_role` | |
1100
+ | `review` | `review: { reviewer_type, criteria, revision_target }` | `revision` エッジと `approved` エッジが**自動生成**される |
1101
+ | `fan_out` | `fan_out_source`, `template` | `template` は sub-graph `{ nodes, edges }` |
1102
+ | `join` | `join_mode`, `aggregation` | |
1103
+ | `conditional` | `condition_type`, `branches` or `default_branch` | |
1104
+ | `transform` | `transform_instruction`, `assigned_role` | |
1105
+
1106
+ **review ノード追加の例:**
1107
+ ```json
1108
+ {
1109
+ "type": "review",
1110
+ "label": "Quality Check",
1111
+ "after": "skill_1",
1112
+ "before": "end",
1113
+ "review": {
1114
+ "reviewer_type": "human",
1115
+ "criteria": "成果物の品質を確認",
1116
+ "revision_target": "skill_1"
1117
+ }
1118
+ }
1119
+ ```
1120
+ → `skill_1 → end` のエッジが削除され、以下が自動生成:
1121
+ - `skill_1 → review_1` (normal)
1122
+ - `review_1 → end` (approved)
1123
+ - `review_1 → skill_1` (revision)
1124
+
1125
+ #### PATCH `/api/minion/dag-workflows/:id/nodes/:nodeId` — ノード更新
1126
+
1127
+ ```json
1128
+ {
1129
+ "label": "Updated Label",
1130
+ "skill_version_id": "<new-version-uuid>",
1131
+ "position": { "x": 200, "y": 100 }
1132
+ }
1133
+ ```
1134
+
1135
+ - 指定したフィールドのみ上書き(未指定フィールドは変更しない)
1136
+ - `position` でノードのエディタ上の座標を更新可能
1137
+ - review ノードの `revision_target` を変更すると、revision エッジが自動で張り替えられる
1138
+ - fan_out ノードの `template` フィールドを上書きすることで、テンプレート sub-graph を更新可能(下記「fan_out テンプレートの編集」参照)
1139
+
1140
+ #### DELETE `/api/minion/dag-workflows/:id/nodes/:nodeId` — ノード削除
1141
+
1142
+ - start / end ノードは削除不可 (400)
1143
+ - 削除されたノードに接続されていたエッジも全て削除される
1144
+ - **自動再接続**: 削除ノードに incoming 1本 + outgoing 1本のエッジがあった場合、それらを直結する新エッジを自動生成
1145
+
1146
+ レスポンス `extra` フィールド:
1147
+ ```json
1148
+ {
1149
+ "removed_node": "skill_2",
1150
+ "removed_edges": ["edge_3", "edge_4"],
1151
+ "reconnected_edge": { "id": "edge_5", "source": "skill_1", "target": "end" }
1152
+ }
1153
+ ```
1154
+
1155
+ #### POST `/api/minion/dag-workflows/:id/edges` — エッジ追加
1156
+
1157
+ ```json
1158
+ {
1159
+ "source": "skill_1",
1160
+ "target": "skill_2",
1161
+ "kind": "normal",
1162
+ "condition_label": "success"
1163
+ }
1164
+ ```
1165
+
1166
+ - `source`, `target` (必須): 既存ノードのID
1167
+ - `kind` (任意): `normal` (default) | `approved` | `revision`
1168
+ - `condition_label` (任意): conditional ノードの分岐ラベル
1169
+ - `id` (任意): 省略時は `edge_1`, `edge_2`, ... で自動採番
1170
+
1171
+ #### PATCH `/api/minion/dag-workflows/:id/edges/:edgeId` — エッジ更新
1172
+
1173
+ ```json
1174
+ {
1175
+ "kind": "approved",
1176
+ "condition_label": "success"
1177
+ }
1178
+ ```
1179
+
1180
+ - `kind` (任意): `normal` | `approved` | `revision`
1181
+ - `condition_label` (任意): 分岐ラベル。`null` を渡すとクリア
1182
+ - 指定したフィールドのみ上書き(未指定フィールドは変更しない)
1183
+
1184
+ #### DELETE `/api/minion/dag-workflows/:id/edges/:edgeId` — エッジ削除
1185
+
1186
+ - エッジIDを指定して削除
1187
+
1188
+ #### POST `/api/minion/dag-workflows/:id/validate` — ドラフト検証
1189
+
1190
+ body なし。現在のドラフトを `validateDagGraph` でフル検証し結果を返す。**公開はしない**。
1191
+
1192
+ ```json
1193
+ {
1194
+ "valid": false,
1195
+ "errors": ["Skill node \"skill_1\" must have a skill selected"],
1196
+ "graph_errors": [],
1197
+ "node_errors": {
1198
+ "skill_1": ["Skill node \"skill_1\" must have a skill selected"]
1199
+ }
1200
+ }
1201
+ ```
1202
+
1203
+ #### 全操作共通のレスポンス形式
1204
+
1205
+ ノード/エッジ操作のレスポンスにはワークフロー全体 + `validation` フィールドが含まれる:
1206
+
1207
+ ```json
1208
+ {
1209
+ "id": "...",
1210
+ "draft_graph": { "nodes": [...], "edges": [...] },
1211
+ "...",
1212
+ "validation": {
1213
+ "valid": false,
1214
+ "errors": ["..."],
1215
+ "node_errors": { "node_id": ["..."] }
1216
+ },
1217
+ "added_node": { "id": "skill_1", "type": "skill", "..." }
1218
+ }
1219
+ ```
1220
+
1221
+ `validation.valid` が `true` になれば `hq publish dag-workflow <id>` で公開可能。
1222
+
1223
+ #### fan_out テンプレートの編集
1224
+
1225
+ fan_out ノードの `template`(sub-graph)にノードやエッジを追加するには、PATCH でテンプレート全体を上書きする:
1226
+
1227
+ ```bash
1228
+ # 1. 現在のドラフトを取得して fan_out ノードの template を確認
1229
+ hq fetch dag-workflow <wf-id> | jq '.draft_graph.nodes[] | select(.id == "fan_out_1") | .template'
1230
+
1231
+ # 2. template を編集して PATCH
1232
+ cat > /tmp/u.json <<'EOF'
1233
+ {
1234
+ "template": {
1235
+ "nodes": [
1236
+ { "id": "t_skill", "type": "skill", "label": "Process Item",
1237
+ "skill_id": "<uuid>", "skill_version_id": "<uuid>", "assigned_role": "engineer" }
1238
+ ],
1239
+ "edges": []
1240
+ }
1241
+ }
1242
+ EOF
1243
+ hq dag update-node <wf-id> fan_out_1 /tmp/u.json
1244
+ ```
1245
+
1246
+ テンプレート内部のノード/エッジを個別操作するAPIは現在ない。テンプレートは `template` フィールドの全体上書きで更新すること。テンプレートは start/end ノードを持たない sub-graph であり、バリデーション時に再帰的に検証される。
1247
+
1058
1248
  ### ミニオン CLI ラッパー
1059
1249
 
1060
1250
  以下の `hq` サブコマンドが上記エンドポイントを呼び出す。いずれもリクエスト送信前にローカルで JSON 構文検証を行う。
1061
1251
 
1062
1252
  ```bash
1253
+ # 全文操作 (従来)
1254
+ hq list dag-workflows [project_id] # GET /api/minion/dag-workflows(?project_id=...)
1063
1255
  hq create dag-workflow <body.json> # POST /api/minion/dag-workflows
1064
1256
  hq put dag-workflow <id> <body.json> # PUT /api/minion/dag-workflows/:id
1065
1257
  hq publish dag-workflow <id> # POST /api/minion/dag-workflows/:id/publish
1066
1258
  hq fetch dag-workflow <id> # GET /api/minion/dag-workflows/:id
1067
1259
  hq fetch dag-execution <id> # GET /api/minion/dag-executions/:id
1260
+
1261
+ # ノード/エッジ操作 (推奨)
1262
+ hq dag add-node <wf-id> <body.json> # POST .../nodes
1263
+ hq dag update-node <wf-id> <node-id> <body.json> # PATCH .../nodes/:nodeId
1264
+ hq dag remove-node <wf-id> <node-id> # DELETE .../nodes/:nodeId
1265
+ hq dag add-edge <wf-id> <body.json> # POST .../edges
1266
+ hq dag update-edge <wf-id> <edge-id> <body.json> # PATCH .../edges/:edgeId
1267
+ hq dag remove-edge <wf-id> <edge-id> # DELETE .../edges/:edgeId
1268
+ hq dag validate <wf-id> # POST .../validate
1068
1269
  ```
1069
1270
 
1070
1271
  ### DAG Read Endpoints (チャットコンテキスト用)
@@ -1073,6 +1274,7 @@ hq fetch dag-execution <id> # GET /api/minion/dag-executions/:
1073
1274
 
1074
1275
  | コマンド | 対応エンドポイント | 用途 |
1075
1276
  |---------|-------------------|------|
1277
+ | `hq list dag-workflows [project_id]` | GET `/api/minion/dag-workflows` | DAG ワークフロー一覧(プロジェクトIDで絞込可) |
1076
1278
  | `hq fetch dag-workflow <id>` | GET `/api/minion/dag-workflows/:id` | DAG ワークフロー定義(published graph + draft)取得 |
1077
1279
  | `hq fetch dag-execution <id>` | GET `/api/minion/dag-executions/:id` | DAG 実行詳細(graph_snapshot + node_executions)取得 |
1078
1280
 
@@ -154,6 +154,18 @@ DAG ワークフローは有向非巡回グラフでスキル間の依存関係
154
154
 
155
155
  **HQダッシュボードの DAG エディタ(プロジェクト画面 → 「DAG (beta)」タブ)で GUI 編集**できるほか、**ミニオンからは JSON ベースで編集可能**(PMロールのみ)。ミニオンは実行ランタイムも担当し、`dag-step-poller` デーモンが pending ノードを自動で処理します。
156
156
 
157
+ ### DAG ワークフロー一覧の取得
158
+
159
+ ```bash
160
+ # 自分がメンバーのプロジェクト全体の DAG ワークフロー一覧
161
+ hq list dag-workflows
162
+
163
+ # 特定プロジェクトに絞り込み
164
+ hq list dag-workflows <project-uuid>
165
+ ```
166
+
167
+ レスポンスには各ワークフローの `id`, `name`, `is_active`, `maturity`, `my_role` 等が含まれる。個別の graph 詳細は `hq fetch dag-workflow <id>` で取得する。
168
+
157
169
  ### ミニオンによる DAG ワークフロー編集 (PM のみ)
158
170
 
159
171
  ミニオンは `hq` CLI で DAG ワークフローの graph JSON を直接編集できる。
@@ -246,11 +258,120 @@ hq put dag-workflow <dag-workflow-id> /tmp/dag-update.json
246
258
  hq publish dag-workflow <dag-workflow-id>
247
259
  ```
248
260
 
261
+ #### 5. ノード/エッジ操作 API(推奨)
262
+
263
+ graph 全文を JSON で書く代わりに、ノード・エッジを1つずつ操作するAPIが利用可能。**各操作のレスポンスにバリデーション結果が含まれる**ため、1ステップごとにエラーを確認・修正できる。
264
+
265
+ ```bash
266
+ # 1. 空の DAG を作成
267
+ cat > /tmp/dag-create.json <<'EOF'
268
+ {
269
+ "project_id": "<project-uuid>",
270
+ "name": "my-dag"
271
+ }
272
+ EOF
273
+ hq create dag-workflow /tmp/dag-create.json
274
+ # → id を控える
275
+
276
+ # 2. start/end ノードを追加
277
+ echo '{ "type": "start", "label": "Start" }' > /tmp/n.json
278
+ hq dag add-node <wf-id> /tmp/n.json
279
+
280
+ echo '{ "type": "end", "label": "End" }' > /tmp/n.json
281
+ hq dag add-node <wf-id> /tmp/n.json
282
+
283
+ # 3. start → end をつなぐエッジ
284
+ echo '{ "source": "start_1", "target": "end_1" }' > /tmp/e.json
285
+ hq dag add-edge <wf-id> /tmp/e.json
286
+
287
+ # 4. skill ノードを start と end の間に挿入
288
+ # after + before を指定すると、既存エッジを自動で差し替える
289
+ cat > /tmp/n.json <<'EOF'
290
+ {
291
+ "type": "skill",
292
+ "label": "Fetch Data",
293
+ "after": "start_1",
294
+ "before": "end_1",
295
+ "skill_id": "<skill-uuid>",
296
+ "skill_version_id": "<version-uuid>",
297
+ "assigned_role": "engineer"
298
+ }
299
+ EOF
300
+ hq dag add-node <wf-id> /tmp/n.json
301
+ # → start_1 → end_1 エッジが削除され、start_1 → skill_1 → end_1 に差し替え
302
+
303
+ # 5. review ノードを追加(approved + revision エッジが自動生成)
304
+ cat > /tmp/n.json <<'EOF'
305
+ {
306
+ "type": "review",
307
+ "label": "Quality Check",
308
+ "after": "skill_1",
309
+ "before": "end_1",
310
+ "review": {
311
+ "reviewer_type": "human",
312
+ "criteria": "成果物の品質を確認",
313
+ "revision_target": "skill_1"
314
+ }
315
+ }
316
+ EOF
317
+ hq dag add-node <wf-id> /tmp/n.json
318
+ # → skill_1 → review_1 (normal), review_1 → end_1 (approved), review_1 → skill_1 (revision)
319
+
320
+ # 6. バリデーション確認(公開せずにチェック)
321
+ hq dag validate <wf-id>
322
+ # → { "valid": true, "errors": [], ... } なら公開可能
323
+
324
+ # 7. 公開
325
+ hq publish dag-workflow <wf-id>
326
+ ```
327
+
328
+ **ノード更新・削除:**
329
+
330
+ ```bash
331
+ # ノードのプロパティを更新
332
+ echo '{ "label": "Updated Name", "skill_version_id": "<new-uuid>" }' > /tmp/u.json
333
+ hq dag update-node <wf-id> skill_1 /tmp/u.json
334
+
335
+ # ノード削除(自動再接続あり)
336
+ hq dag remove-node <wf-id> skill_2
337
+
338
+ # エッジの kind や condition_label を更新
339
+ echo '{ "kind": "approved" }' > /tmp/eu.json
340
+ hq dag update-edge <wf-id> edge_3 /tmp/eu.json
341
+
342
+ # エッジ削除
343
+ hq dag remove-edge <wf-id> edge_3
344
+ ```
345
+
346
+ **fan_out テンプレート編集:**
347
+
348
+ ```bash
349
+ # fan_out ノードの template を PATCH で上書き
350
+ cat > /tmp/t.json <<'EOF'
351
+ {
352
+ "template": {
353
+ "nodes": [
354
+ { "id": "t_skill", "type": "skill", "label": "Process Item",
355
+ "skill_id": "<uuid>", "skill_version_id": "<uuid>", "assigned_role": "engineer" }
356
+ ],
357
+ "edges": []
358
+ }
359
+ }
360
+ EOF
361
+ hq dag update-node <wf-id> fan_out_1 /tmp/t.json
362
+ ```
363
+
364
+ **Tips:**
365
+ - `hq dag add-node` で review ノードを追加すると、`approved` エッジと `revision` エッジが自動生成される。手動でエッジを張る必要なし
366
+ - 各操作のレスポンスの `validation.valid` が `true` かどうかで、いつでも公開可能かを判断できる
367
+ - 複雑なグラフでも1ノードずつ積み上げれば、途中でバリデーションエラーの原因を特定しやすい
368
+
249
369
  #### 権限と注意事項
250
370
 
251
- - 書き込み(create / put / publish)は **PMロールのみ**。Engineer / accountant では 403 が返る。読み取り(fetch)は全メンバー可。
252
- - ドラフト保存は軽量(構造チェックのみ)。インクリメンタルに graph を組み立てていくのに適している。
253
- - セマンティックエラーは publish 時にまとめて検出されるため、途中保存と最終公開を使い分けること。
371
+ - 書き込み(create / put / publish / dag 操作)は **PMロールのみ**。Engineer / accountant では 403 が返る。読み取り(fetch)は全メンバー可。
372
+ - ノード/エッジ操作は各ステップでドラフトに自動保存され、バリデーション結果がレスポンスに含まれる。
373
+ - `hq dag validate` で公開前にフル検証できる。publish 時の想定外エラーを防止できる。
374
+ - 全文 JSON 操作(`hq put dag-workflow`)も引き続き利用可能だが、**ノード/エッジ操作APIの方が推奨**。
254
375
 
255
376
  ### 実行フロー(ランタイム側、参考)
256
377
 
package/linux/bin/hq CHANGED
@@ -17,6 +17,7 @@
17
17
  # hq fetch dag-workflow <id> - Get DAG workflow details (graph, version)
18
18
  # hq fetch dag-execution <id> - Get DAG execution details (nodes, status)
19
19
  # hq list workspaces - List workspaces this minion belongs to
20
+ # hq list dag-workflows [project_id] - List DAG workflows (optionally filter by project)
20
21
  # hq note create <project_id> --title "Title" --content "Body" [--file path]
21
22
  # - Create a note linked to the project
22
23
  # hq note update <project_id> <note_id> --content "Body" [--title "Title"] [--file path] [--change-summary "summary"]
@@ -27,6 +28,13 @@
27
28
  # hq create dag-workflow <body.json> - Create a DAG workflow (PM only). Body: {project_id, name, graph?, ...}
28
29
  # hq put dag-workflow <id> <body.json> - Update DAG workflow draft (PM only). Body: {graph?, content?, ...}
29
30
  # hq publish dag-workflow <id> - Publish the draft as a new version (PM only, validated)
31
+ # hq dag add-node <wf-id> <body.json> - Add a node to DAG draft. Body: {type, label?, after?, before?, ...}
32
+ # hq dag update-node <wf-id> <node-id> <body.json> - Update a node. Body: {label?, skill_version_id?, ...}
33
+ # hq dag remove-node <wf-id> <node-id> - Remove a node (auto-reconnects if possible)
34
+ # hq dag add-edge <wf-id> <body.json> - Add an edge. Body: {source, target, kind?, condition_label?}
35
+ # hq dag update-edge <wf-id> <edge-id> <body.json> - Update edge kind/condition_label
36
+ # hq dag remove-edge <wf-id> <edge-id> - Remove an edge
37
+ # hq dag validate <wf-id> - Validate draft without publishing
30
38
 
31
39
  set -euo pipefail
32
40
 
@@ -95,7 +103,7 @@ fetch_resource() {
95
103
  fi
96
104
  }
97
105
 
98
- # Send a JSON request body from a file. Method is POST or PUT.
106
+ # Send a JSON request body from a file. Method is POST, PUT, or PATCH.
99
107
  send_json_request() {
100
108
  local method="$1"
101
109
  local url="$2"
@@ -153,6 +161,7 @@ print_usage() {
153
161
  echo " hq fetch dag-workflow <id> - Get DAG workflow details" >&2
154
162
  echo " hq fetch dag-execution <id> - Get DAG execution details" >&2
155
163
  echo " hq list workspaces - List workspaces this minion belongs to" >&2
164
+ echo " hq list dag-workflows [project_id] - List DAG workflows (optionally by project)" >&2
156
165
  echo " hq note create <project_id> --title \"Title\" --content \"Body\" [--file path]" >&2
157
166
  echo " hq note update <project_id> <note_id> --content \"Body\" [--title \"Title\"] [--file path]" >&2
158
167
  echo " hq note list <project_id> - List notes in the project" >&2
@@ -161,6 +170,15 @@ print_usage() {
161
170
  echo " hq create dag-workflow <body.json> - Create a DAG workflow (PM only)" >&2
162
171
  echo " hq put dag-workflow <id> <body.json> - Update DAG workflow draft (PM only)" >&2
163
172
  echo " hq publish dag-workflow <id> - Publish the draft as a new version (PM only)" >&2
173
+ echo "" >&2
174
+ echo " DAG node/edge operations (PM only, each returns validation warnings):" >&2
175
+ echo " hq dag add-node <wf-id> <body.json> - Add a node to DAG draft" >&2
176
+ echo " hq dag update-node <wf-id> <node-id> <body.json> - Update a node's properties" >&2
177
+ echo " hq dag remove-node <wf-id> <node-id> - Remove a node" >&2
178
+ echo " hq dag add-edge <wf-id> <body.json> - Add an edge" >&2
179
+ echo " hq dag update-edge <wf-id> <edge-id> <body.json> - Update edge kind/label" >&2
180
+ echo " hq dag remove-edge <wf-id> <edge-id> - Remove an edge" >&2
181
+ echo " hq dag validate <wf-id> - Validate draft (no publish)" >&2
164
182
  }
165
183
 
166
184
  # Main command dispatch
@@ -212,9 +230,17 @@ case "${1:-}" in
212
230
  workspaces)
213
231
  fetch_resource "$BASE_URL/workspaces"
214
232
  ;;
233
+ dag-workflows)
234
+ project_filter="${3:-}"
235
+ if [ -n "$project_filter" ]; then
236
+ fetch_resource "$BASE_URL/dag-workflows?project_id=$project_filter"
237
+ else
238
+ fetch_resource "$BASE_URL/dag-workflows"
239
+ fi
240
+ ;;
215
241
  *)
216
242
  echo "Unknown list resource: $resource" >&2
217
- echo "Usage: hq list workspaces" >&2
243
+ echo "Usage: hq list {workspaces|dag-workflows}" >&2
218
244
  exit 1
219
245
  ;;
220
246
  esac
@@ -444,6 +470,112 @@ print(json.dumps(d))
444
470
  esac
445
471
  ;;
446
472
 
473
+ dag)
474
+ action="${2:-}"
475
+ case "$action" in
476
+ add-node)
477
+ wf_id="${3:-}"
478
+ body_file="${4:-}"
479
+ if [ -z "$wf_id" ] || [ -z "$body_file" ]; then
480
+ echo "Usage: hq dag add-node <wf-id> <body.json>" >&2
481
+ echo " body.json: { type, label?, after?, before?, skill_id?, skill_version_id?, assigned_role?, review?, ... }" >&2
482
+ exit 1
483
+ fi
484
+ validate_json_file "$body_file"
485
+ send_json_request POST "$BASE_URL/dag-workflows/$wf_id/nodes" "$body_file"
486
+ ;;
487
+ update-node)
488
+ wf_id="${3:-}"
489
+ node_id="${4:-}"
490
+ body_file="${5:-}"
491
+ if [ -z "$wf_id" ] || [ -z "$node_id" ] || [ -z "$body_file" ]; then
492
+ echo "Usage: hq dag update-node <wf-id> <node-id> <body.json>" >&2
493
+ echo " body.json: { label?, skill_version_id?, assigned_role?, review?, ... }" >&2
494
+ exit 1
495
+ fi
496
+ validate_json_file "$body_file"
497
+ send_json_request PATCH "$BASE_URL/dag-workflows/$wf_id/nodes/$node_id" "$body_file"
498
+ ;;
499
+ remove-node)
500
+ wf_id="${3:-}"
501
+ node_id="${4:-}"
502
+ if [ -z "$wf_id" ] || [ -z "$node_id" ]; then
503
+ echo "Usage: hq dag remove-node <wf-id> <node-id>" >&2
504
+ exit 1
505
+ fi
506
+ # DELETE with no body
507
+ response=$(curl -s -w "\n%{http_code}" -X DELETE \
508
+ -H "Authorization: Bearer $API_TOKEN" \
509
+ "$BASE_URL/dag-workflows/$wf_id/nodes/$node_id")
510
+ http_code=$(echo "$response" | tail -1)
511
+ body=$(echo "$response" | sed '$d')
512
+ if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
513
+ echo "$body" | format_json
514
+ else
515
+ echo "Error: HQ API returned HTTP $http_code" >&2
516
+ echo "$body" >&2
517
+ exit 1
518
+ fi
519
+ ;;
520
+ add-edge)
521
+ wf_id="${3:-}"
522
+ body_file="${4:-}"
523
+ if [ -z "$wf_id" ] || [ -z "$body_file" ]; then
524
+ echo "Usage: hq dag add-edge <wf-id> <body.json>" >&2
525
+ echo " body.json: { source, target, kind?, condition_label? }" >&2
526
+ exit 1
527
+ fi
528
+ validate_json_file "$body_file"
529
+ send_json_request POST "$BASE_URL/dag-workflows/$wf_id/edges" "$body_file"
530
+ ;;
531
+ update-edge)
532
+ wf_id="${3:-}"
533
+ edge_id="${4:-}"
534
+ body_file="${5:-}"
535
+ if [ -z "$wf_id" ] || [ -z "$edge_id" ] || [ -z "$body_file" ]; then
536
+ echo "Usage: hq dag update-edge <wf-id> <edge-id> <body.json>" >&2
537
+ echo " body.json: { kind?, condition_label? }" >&2
538
+ exit 1
539
+ fi
540
+ validate_json_file "$body_file"
541
+ send_json_request PATCH "$BASE_URL/dag-workflows/$wf_id/edges/$edge_id" "$body_file"
542
+ ;;
543
+ remove-edge)
544
+ wf_id="${3:-}"
545
+ edge_id="${4:-}"
546
+ if [ -z "$wf_id" ] || [ -z "$edge_id" ]; then
547
+ echo "Usage: hq dag remove-edge <wf-id> <edge-id>" >&2
548
+ exit 1
549
+ fi
550
+ response=$(curl -s -w "\n%{http_code}" -X DELETE \
551
+ -H "Authorization: Bearer $API_TOKEN" \
552
+ "$BASE_URL/dag-workflows/$wf_id/edges/$edge_id")
553
+ http_code=$(echo "$response" | tail -1)
554
+ body=$(echo "$response" | sed '$d')
555
+ if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
556
+ echo "$body" | format_json
557
+ else
558
+ echo "Error: HQ API returned HTTP $http_code" >&2
559
+ echo "$body" >&2
560
+ exit 1
561
+ fi
562
+ ;;
563
+ validate)
564
+ wf_id="${3:-}"
565
+ if [ -z "$wf_id" ]; then
566
+ echo "Usage: hq dag validate <wf-id>" >&2
567
+ exit 1
568
+ fi
569
+ send_empty_post "$BASE_URL/dag-workflows/$wf_id/validate"
570
+ ;;
571
+ *)
572
+ echo "Unknown dag action: $action" >&2
573
+ echo "Usage: hq dag {add-node|update-node|remove-node|add-edge|remove-edge|validate} ..." >&2
574
+ exit 1
575
+ ;;
576
+ esac
577
+ ;;
578
+
447
579
  *)
448
580
  print_usage
449
581
  exit 1
@@ -403,10 +403,17 @@ async function buildContextPrefix(message, context, sessionId, workspaceId) {
403
403
  ` hq fetch dag-workflow ${context.dagWorkflowId}`,
404
404
  `プロジェクトコンテキスト:`,
405
405
  ` hq fetch project-context ${context.projectId}`,
406
- `PMロールの場合、graph JSON を直接編集できます:`,
407
- ` hq put dag-workflow ${context.dagWorkflowId} <body.json> # ドラフト更新 (構造チェックのみ)`,
408
- ` hq publish dag-workflow ${context.dagWorkflowId} # ドラフトを新バージョンとして公開 (フル検証)`,
406
+ `PMロールの場合、ノード/エッジ操作APIでインクリメンタルに編集できます(推奨):`,
407
+ ` hq dag add-node ${context.dagWorkflowId} <body.json> # ノード追加`,
408
+ ` hq dag update-node ${context.dagWorkflowId} <node-id> <body.json> # ノード更新`,
409
+ ` hq dag remove-node ${context.dagWorkflowId} <node-id> # ノード削除`,
410
+ ` hq dag add-edge ${context.dagWorkflowId} <body.json> # エッジ追加`,
411
+ ` hq dag remove-edge ${context.dagWorkflowId} <edge-id> # エッジ削除`,
412
+ ` hq dag validate ${context.dagWorkflowId} # ドラフト検証(公開せず)`,
413
+ ` hq publish dag-workflow ${context.dagWorkflowId} # 公開`,
414
+ `graph JSON 全文操作も可能: hq put dag-workflow ${context.dagWorkflowId} <body.json>`,
409
415
  `新規作成は: hq create dag-workflow <body.json>`,
416
+ `プロジェクト内の DAG ワークフロー一覧: hq list dag-workflows ${context.projectId}`,
410
417
  `DAG の構造(nodes/edges/node types/scope_path 等)や実行フローの詳細は ~/.minion/docs/api-reference.md の「DAG Workflows」セクション、および ~/.minion/docs/task-guides.md の「DAG ワークフロー」セクションを参照してください。`,
411
418
  `取得した内容をもとに回答してください。`
412
419
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekbeer/minion",
3
- "version": "3.27.1",
3
+ "version": "3.29.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": {
package/win/bin/hq.ps1 CHANGED
@@ -22,6 +22,13 @@
22
22
  .\hq.ps1 create dag-workflow <body.json>
23
23
  .\hq.ps1 put dag-workflow <id> <body.json>
24
24
  .\hq.ps1 publish dag-workflow <id>
25
+ .\hq.ps1 dag add-node <wf-id> <body.json>
26
+ .\hq.ps1 dag update-node <wf-id> <node-id> <body.json>
27
+ .\hq.ps1 dag remove-node <wf-id> <node-id>
28
+ .\hq.ps1 dag add-edge <wf-id> <body.json>
29
+ .\hq.ps1 dag update-edge <wf-id> <edge-id> <body.json>
30
+ .\hq.ps1 dag remove-edge <wf-id> <edge-id>
31
+ .\hq.ps1 dag validate <wf-id>
25
32
  #>
26
33
 
27
34
  param(
@@ -35,7 +42,10 @@ param(
35
42
  [string]$Arg2,
36
43
 
37
44
  [Parameter(Position = 3)]
38
- [string]$Arg3
45
+ [string]$Arg3,
46
+
47
+ [Parameter(Position = 4)]
48
+ [string]$Arg4
39
49
  )
40
50
 
41
51
  $ErrorActionPreference = 'Stop'
@@ -129,9 +139,19 @@ function Show-Usage {
129
139
  Write-Host " hq fetch dag-workflow <id> - Get DAG workflow details"
130
140
  Write-Host " hq fetch dag-execution <id> - Get DAG execution details"
131
141
  Write-Host " hq list workspaces - List workspaces this minion belongs to"
142
+ Write-Host " hq list dag-workflows [project_id] - List DAG workflows (optionally by project)"
132
143
  Write-Host " hq create dag-workflow <body.json> - Create a DAG workflow (PM only)"
133
144
  Write-Host " hq put dag-workflow <id> <body.json> - Update DAG workflow draft (PM only)"
134
145
  Write-Host " hq publish dag-workflow <id> - Publish the draft as a new version (PM only)"
146
+ Write-Host ""
147
+ Write-Host " DAG node/edge operations (PM only, each returns validation warnings):"
148
+ Write-Host " hq dag add-node <wf-id> <body.json> - Add a node to DAG draft"
149
+ Write-Host " hq dag update-node <wf-id> <node-id> <body.json> - Update a node's properties"
150
+ Write-Host " hq dag remove-node <wf-id> <node-id> - Remove a node"
151
+ Write-Host " hq dag add-edge <wf-id> <body.json> - Add an edge"
152
+ Write-Host " hq dag update-edge <wf-id> <edge-id> <body.json> - Update edge kind/label"
153
+ Write-Host " hq dag remove-edge <wf-id> <edge-id> - Remove an edge"
154
+ Write-Host " hq dag validate <wf-id> - Validate draft (no publish)"
135
155
  }
136
156
 
137
157
  switch ($Command) {
@@ -172,9 +192,17 @@ switch ($Command) {
172
192
  $Resource = $Arg1
173
193
  switch ($Resource) {
174
194
  'workspaces' { Invoke-HqApi "$BaseUrl/workspaces" }
195
+ 'dag-workflows' {
196
+ $ProjectFilter = $Arg2
197
+ if ($ProjectFilter) {
198
+ Invoke-HqApi "$BaseUrl/dag-workflows?project_id=$ProjectFilter"
199
+ } else {
200
+ Invoke-HqApi "$BaseUrl/dag-workflows"
201
+ }
202
+ }
175
203
  default {
176
204
  Write-Error "Unknown list resource: $Resource"
177
- Write-Error "Usage: hq list workspaces"
205
+ Write-Error "Usage: hq list {workspaces|dag-workflows}"
178
206
  exit 1
179
207
  }
180
208
  }
@@ -242,6 +270,105 @@ switch ($Command) {
242
270
  }
243
271
  }
244
272
 
273
+ 'dag' {
274
+ $Action = $Arg1
275
+ switch ($Action) {
276
+ 'add-node' {
277
+ $WfId = $Arg2
278
+ $BodyFile = $Arg3
279
+ if (-not $WfId -or -not $BodyFile) {
280
+ Write-Error "Usage: hq dag add-node <wf-id> <body.json>"
281
+ exit 1
282
+ }
283
+ Assert-ValidJsonFile -Path $BodyFile
284
+ Send-JsonRequest -Method 'Post' -Url "$BaseUrl/dag-workflows/$WfId/nodes" -Path $BodyFile
285
+ }
286
+ 'update-node' {
287
+ $WfId = $Arg2
288
+ $NodeId = $Arg3
289
+ $BodyFile = $Arg4
290
+ if (-not $WfId -or -not $NodeId -or -not $BodyFile) {
291
+ Write-Error "Usage: hq dag update-node <wf-id> <node-id> <body.json>"
292
+ exit 1
293
+ }
294
+ Assert-ValidJsonFile -Path $BodyFile
295
+ Send-JsonRequest -Method 'Patch' -Url "$BaseUrl/dag-workflows/$WfId/nodes/$NodeId" -Path $BodyFile
296
+ }
297
+ 'remove-node' {
298
+ $WfId = $Arg2
299
+ $NodeId = $Arg3
300
+ if (-not $WfId -or -not $NodeId) {
301
+ Write-Error "Usage: hq dag remove-node <wf-id> <node-id>"
302
+ exit 1
303
+ }
304
+ try {
305
+ $response = Invoke-RestMethod -Uri "$BaseUrl/dag-workflows/$WfId/nodes/$NodeId" `
306
+ -Headers $Headers -Method Delete -ErrorAction Stop
307
+ $response | ConvertTo-Json -Depth 20
308
+ }
309
+ catch {
310
+ $statusCode = $_.Exception.Response.StatusCode.value__
311
+ Write-Error "Error: HQ API returned HTTP $statusCode"
312
+ Write-Error $_.ErrorDetails.Message
313
+ exit 1
314
+ }
315
+ }
316
+ 'add-edge' {
317
+ $WfId = $Arg2
318
+ $BodyFile = $Arg3
319
+ if (-not $WfId -or -not $BodyFile) {
320
+ Write-Error "Usage: hq dag add-edge <wf-id> <body.json>"
321
+ exit 1
322
+ }
323
+ Assert-ValidJsonFile -Path $BodyFile
324
+ Send-JsonRequest -Method 'Post' -Url "$BaseUrl/dag-workflows/$WfId/edges" -Path $BodyFile
325
+ }
326
+ 'update-edge' {
327
+ $WfId = $Arg2
328
+ $EdgeId = $Arg3
329
+ $BodyFile = $Arg4
330
+ if (-not $WfId -or -not $EdgeId -or -not $BodyFile) {
331
+ Write-Error "Usage: hq dag update-edge <wf-id> <edge-id> <body.json>"
332
+ exit 1
333
+ }
334
+ Assert-ValidJsonFile -Path $BodyFile
335
+ Send-JsonRequest -Method 'Patch' -Url "$BaseUrl/dag-workflows/$WfId/edges/$EdgeId" -Path $BodyFile
336
+ }
337
+ 'remove-edge' {
338
+ $WfId = $Arg2
339
+ $EdgeId = $Arg3
340
+ if (-not $WfId -or -not $EdgeId) {
341
+ Write-Error "Usage: hq dag remove-edge <wf-id> <edge-id>"
342
+ exit 1
343
+ }
344
+ try {
345
+ $response = Invoke-RestMethod -Uri "$BaseUrl/dag-workflows/$WfId/edges/$EdgeId" `
346
+ -Headers $Headers -Method Delete -ErrorAction Stop
347
+ $response | ConvertTo-Json -Depth 20
348
+ }
349
+ catch {
350
+ $statusCode = $_.Exception.Response.StatusCode.value__
351
+ Write-Error "Error: HQ API returned HTTP $statusCode"
352
+ Write-Error $_.ErrorDetails.Message
353
+ exit 1
354
+ }
355
+ }
356
+ 'validate' {
357
+ $WfId = $Arg2
358
+ if (-not $WfId) {
359
+ Write-Error "Usage: hq dag validate <wf-id>"
360
+ exit 1
361
+ }
362
+ Send-EmptyPost -Url "$BaseUrl/dag-workflows/$WfId/validate"
363
+ }
364
+ default {
365
+ Write-Error "Unknown dag action: $Action"
366
+ Write-Error "Usage: hq dag {add-node|update-node|remove-node|add-edge|remove-edge|validate} ..."
367
+ exit 1
368
+ }
369
+ }
370
+ }
371
+
245
372
  default {
246
373
  Show-Usage
247
374
  exit 1
@@ -464,10 +464,17 @@ async function buildContextPrefix(message, context, sessionId, workspaceId) {
464
464
  ` hq fetch dag-workflow ${context.dagWorkflowId}`,
465
465
  `プロジェクトコンテキスト:`,
466
466
  ` hq fetch project-context ${context.projectId}`,
467
- `PMロールの場合、graph JSON を直接編集できます:`,
468
- ` hq put dag-workflow ${context.dagWorkflowId} <body.json> # ドラフト更新 (構造チェックのみ)`,
469
- ` hq publish dag-workflow ${context.dagWorkflowId} # ドラフトを新バージョンとして公開 (フル検証)`,
467
+ `PMロールの場合、ノード/エッジ操作APIでインクリメンタルに編集できます(推奨):`,
468
+ ` hq dag add-node ${context.dagWorkflowId} <body.json> # ノード追加`,
469
+ ` hq dag update-node ${context.dagWorkflowId} <node-id> <body.json> # ノード更新`,
470
+ ` hq dag remove-node ${context.dagWorkflowId} <node-id> # ノード削除`,
471
+ ` hq dag add-edge ${context.dagWorkflowId} <body.json> # エッジ追加`,
472
+ ` hq dag remove-edge ${context.dagWorkflowId} <edge-id> # エッジ削除`,
473
+ ` hq dag validate ${context.dagWorkflowId} # ドラフト検証(公開せず)`,
474
+ ` hq publish dag-workflow ${context.dagWorkflowId} # 公開`,
475
+ `graph JSON 全文操作も可能: hq put dag-workflow ${context.dagWorkflowId} <body.json>`,
470
476
  `新規作成は: hq create dag-workflow <body.json>`,
477
+ `プロジェクト内の DAG ワークフロー一覧: hq list dag-workflows ${context.projectId}`,
471
478
  `DAG の構造(nodes/edges/node types/scope_path 等)や実行フローの詳細は ~/.minion/docs/api-reference.md の「DAG Workflows」セクション、および ~/.minion/docs/task-guides.md の「DAG ワークフロー」セクションを参照してください。`,
472
479
  `取得した内容をもとに回答してください。`
473
480
  )