flower-trellis 0.3.1-beta.6 → 0.3.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.
@@ -60,7 +60,9 @@ python3 .agents/skills/trellis-route/scripts/route_state.py resolve --target <im
60
60
  python3 .claude/skills/trellis-route/scripts/route_state.py resolve --target <implement|check>
61
61
  ```
62
62
 
63
- helper 只接受当前 session 或唯一 session fallback 的 `.trellis/.runtime/sessions/<context-key>.json`,并只从 `route_decisions.<target>` 恢复决策。命中时输出 `{"status":"hit", ...}`,其中 `decision` 已经过 task/target/source/mode/scope 校验,可跳过 Step 2 并进入 Step 3 输出决策。`source=route-prefs` `wrote_runtime=true` 时,输出模板同时写明来自个人 route 配置和已写入 session runtime state。
63
+ helper 只接受当前 session 或唯一 session fallback 的 `.trellis/.runtime/sessions/<context-key>.json`,并只从 `route_decisions.<target>` 恢复决策。命中时输出 `{"status":"hit", ...}`,其中默认输出里的 `mode` / `source` 已经过 task/target/source/mode/scope 校验,可跳过 Step 2 并进入 Step 3 输出决策。`origin=route-prefs` 表示来自个人 route 配置,并且 helper 已写回 session runtime state;`origin=runtime` 表示来自 session runtime state
64
+
65
+ helper 默认输出为精简 JSON,只包含 route 执行必需的 `status`、`origin`、`mode`、`source`/`reason` 等字段。需要排查完整 `decision`、session 文件、context key、任务路径、个人配置路径或写回标记时,在同一命令末尾加 `--verbose`;不要为了诊断信息额外读取 runtime 文件。
64
66
 
65
67
  输出 `status=miss`、文件缺失、JSON 损坏、任务不匹配、source/mode 不合法、prefs 缺失或 prefs 值不合法时,忽略已有状态并继续 Step 2。不要删除不匹配 runtime 文件,避免误伤其他窗口。
66
68
 
@@ -212,7 +214,6 @@ route_decision:
212
214
  mode: <inline | subagent | check-all-inline | check-all-subagent | check-inline | check-subagent>
213
215
  source: <trellis-route | route-prefs | numbered-fallback>
214
216
  scope: task
215
- task: <task.py current 的任务路径或 current>
216
217
 
217
218
  接下来主 agent 应当:
218
219
  - <路由表里对应的工具调用形式>
@@ -222,7 +223,7 @@ route_decision:
222
223
  - <要避免的工具调用>
223
224
  ```
224
225
 
225
- 中括号内行为条件性出现:仅命中个人配置时显示配置行;仅命中 runtime state 时显示“来自”行;写入 runtime state 成功时显示“已写入”行;仅轻量 check 时显示隐藏逃生口说明;仅 implement subagent + skip_compile=true 时附加“跳过编译”段。`route_decision` 必须保留在回复中;compact summary 若只有自然语言描述,后续 agent 仍应优先读取 runtime state,而不是把 summary 当证据。
226
+ 中括号内行为条件性出现:仅命中个人配置时显示配置行;仅命中 runtime state 时显示“来自”行;写入 runtime state 成功时显示“已写入”行;仅轻量 check 时显示隐藏逃生口说明;仅 implement subagent + skip_compile=true 时附加“跳过编译”段。`route_decision` 必须保留在回复中,但默认只保留 target/mode/source/scope;需要 task/path/decided_at 等诊断字段时重新调用 helper 并加 `--verbose`。compact summary 若只有自然语言描述,后续 agent 仍应优先读取 runtime state,而不是把 summary 当证据。
226
227
 
227
228
  ---
228
229
 
@@ -73,6 +73,21 @@ def _print(data: dict[str, Any]) -> int:
73
73
  return 0
74
74
 
75
75
 
76
+ def _output(args: argparse.Namespace, data: dict[str, Any], verbose: dict[str, Any] | None = None) -> int:
77
+ """按默认精简模式或详细模式输出 JSON。"""
78
+ if getattr(args, "verbose", False) and verbose:
79
+ data = {**data, **verbose}
80
+ return _print(data)
81
+
82
+
83
+ def _decision_summary(decision: dict[str, Any]) -> dict[str, Any]:
84
+ """提取默认输出需要的最小 route 决策字段。"""
85
+ return {
86
+ "mode": decision.get("mode"),
87
+ "source": decision.get("source"),
88
+ }
89
+
90
+
76
91
  def _current_task(repo_root: Path) -> tuple[str | None, str | None, str | None]:
77
92
  """通过 task.py current --source 获取当前任务和 session key。"""
78
93
  result = subprocess.run(
@@ -236,20 +251,27 @@ def read_runtime(args: argparse.Namespace) -> int:
236
251
  context = _read_json(path)
237
252
  decision = context.get("route_decisions", {}).get(args.target)
238
253
  if _valid_decision(decision, args.target, current_task):
239
- return _print(
254
+ return _output(
255
+ args,
240
256
  {
241
257
  "status": "hit",
258
+ **_decision_summary(decision),
259
+ },
260
+ {
261
+ "decision": decision,
242
262
  "path": _rel_path(repo_root, path),
243
263
  "context_key": context_key,
244
264
  "task": current_task,
245
- "decision": decision,
246
265
  }
247
266
  )
248
267
 
249
- return _print(
268
+ return _output(
269
+ args,
250
270
  {
251
271
  "status": "miss",
252
272
  "reason": "no-valid-decision",
273
+ },
274
+ {
253
275
  "path": _rel_path(repo_root, path),
254
276
  "context_key": context_key,
255
277
  "task": current_task,
@@ -272,14 +294,18 @@ def resolve_route(args: argparse.Namespace) -> int:
272
294
  context = _read_json(path)
273
295
  decision = context.get("route_decisions", {}).get(args.target)
274
296
  if _valid_decision(decision, args.target, current_task):
275
- return _print(
297
+ return _output(
298
+ args,
276
299
  {
277
300
  "status": "hit",
278
- "source": "runtime",
301
+ "origin": "runtime",
302
+ **_decision_summary(decision),
303
+ },
304
+ {
305
+ "decision": decision,
279
306
  "path": _rel_path(repo_root, path),
280
307
  "context_key": context_key,
281
308
  "task": current_task,
282
- "decision": decision,
283
309
  }
284
310
  )
285
311
 
@@ -294,23 +320,30 @@ def resolve_route(args: argparse.Namespace) -> int:
294
320
  pref_mode,
295
321
  "route-prefs",
296
322
  )
297
- return _print(
323
+ return _output(
324
+ args,
298
325
  {
299
326
  "status": "hit",
300
- "source": "route-prefs",
327
+ "origin": "route-prefs",
328
+ **_decision_summary(pref_decision),
329
+ },
330
+ {
331
+ "decision": pref_decision,
301
332
  "path": _rel_path(repo_root, written_path),
302
333
  "pref_path": _rel_path(repo_root, _pref_path(repo_root)),
303
334
  "context_key": context_key,
304
335
  "task": current_task,
305
- "decision": pref_decision,
306
336
  "wrote_runtime": True,
307
337
  }
308
338
  )
309
339
 
310
- return _print(
340
+ return _output(
341
+ args,
311
342
  {
312
343
  "status": "miss",
313
344
  "reason": "no-valid-decision-or-pref",
345
+ },
346
+ {
314
347
  "path": _rel_path(repo_root, path),
315
348
  "pref_path": _rel_path(repo_root, _pref_path(repo_root)),
316
349
  "context_key": context_key,
@@ -365,14 +398,18 @@ def write_route(args: argparse.Namespace) -> int:
365
398
  args.mode,
366
399
  args.source,
367
400
  )
368
- return _print(
401
+ return _output(
402
+ args,
369
403
  {
370
404
  "status": "written",
405
+ **_decision_summary(decision),
406
+ },
407
+ {
408
+ "decision": decision,
371
409
  "path": _rel_path(repo_root, path),
372
410
  "pref_path": _rel_path(repo_root, _pref_path(repo_root)) if args.save_pref else None,
373
411
  "context_key": context_key,
374
412
  "task": current_task,
375
- "decision": decision,
376
413
  "saved_pref": bool(args.save_pref),
377
414
  }
378
415
  )
@@ -387,10 +424,13 @@ def clear_pref(args: argparse.Namespace) -> int:
387
424
  existed = args.target in prefs
388
425
  prefs.pop(args.target, None)
389
426
  _write_prefs(repo_root, prefs)
390
- return _print(
427
+ return _output(
428
+ args,
391
429
  {
392
430
  "status": "cleared",
393
431
  "target": args.target,
432
+ },
433
+ {
394
434
  "existed": existed,
395
435
  "pref_path": _rel_path(repo_root, _pref_path(repo_root)),
396
436
  }
@@ -404,10 +444,12 @@ def build_parser() -> argparse.ArgumentParser:
404
444
 
405
445
  resolve_parser = subparsers.add_parser("resolve", help="resolve route from runtime then prefs")
406
446
  resolve_parser.add_argument("--target", choices=sorted(VALID_MODES), required=True)
447
+ resolve_parser.add_argument("--verbose", action="store_true", help="include diagnostic paths and session metadata")
407
448
  resolve_parser.set_defaults(func=resolve_route)
408
449
 
409
450
  read_parser = subparsers.add_parser("read-runtime", help="read a runtime route decision")
410
451
  read_parser.add_argument("--target", choices=sorted(VALID_MODES), required=True)
452
+ read_parser.add_argument("--verbose", action="store_true", help="include diagnostic paths and session metadata")
411
453
  read_parser.set_defaults(func=read_runtime)
412
454
 
413
455
  write_parser = subparsers.add_parser("write", help="write a route decision")
@@ -415,10 +457,12 @@ def build_parser() -> argparse.ArgumentParser:
415
457
  write_parser.add_argument("--mode", required=True)
416
458
  write_parser.add_argument("--source", choices=sorted(VALID_SOURCES), required=True)
417
459
  write_parser.add_argument("--save-pref", action="store_true")
460
+ write_parser.add_argument("--verbose", action="store_true", help="include diagnostic paths and session metadata")
418
461
  write_parser.set_defaults(func=write_route)
419
462
 
420
463
  clear_parser = subparsers.add_parser("clear-pref", help="clear a personal route preference")
421
464
  clear_parser.add_argument("--target", choices=sorted(PREF_MODES), required=True)
465
+ clear_parser.add_argument("--verbose", action="store_true", help="include diagnostic paths and preference metadata")
422
466
  clear_parser.set_defaults(func=clear_pref)
423
467
 
424
468
  return parser
@@ -60,7 +60,9 @@ python3 .agents/skills/trellis-route/scripts/route_state.py resolve --target <im
60
60
  python3 .claude/skills/trellis-route/scripts/route_state.py resolve --target <implement|check>
61
61
  ```
62
62
 
63
- helper 只接受当前 session 或唯一 session fallback 的 `.trellis/.runtime/sessions/<context-key>.json`,并只从 `route_decisions.<target>` 恢复决策。命中时输出 `{"status":"hit", ...}`,其中 `decision` 已经过 task/target/source/mode/scope 校验,可跳过 Step 2 并进入 Step 3 输出决策。`source=route-prefs` `wrote_runtime=true` 时,输出模板同时写明来自个人 route 配置和已写入 session runtime state。
63
+ helper 只接受当前 session 或唯一 session fallback 的 `.trellis/.runtime/sessions/<context-key>.json`,并只从 `route_decisions.<target>` 恢复决策。命中时输出 `{"status":"hit", ...}`,其中默认输出里的 `mode` / `source` 已经过 task/target/source/mode/scope 校验,可跳过 Step 2 并进入 Step 3 输出决策。`origin=route-prefs` 表示来自个人 route 配置,并且 helper 已写回 session runtime state;`origin=runtime` 表示来自 session runtime state
64
+
65
+ helper 默认输出为精简 JSON,只包含 route 执行必需的 `status`、`origin`、`mode`、`source`/`reason` 等字段。需要排查完整 `decision`、session 文件、context key、任务路径、个人配置路径或写回标记时,在同一命令末尾加 `--verbose`;不要为了诊断信息额外读取 runtime 文件。
64
66
 
65
67
  输出 `status=miss`、文件缺失、JSON 损坏、任务不匹配、source/mode 不合法、prefs 缺失或 prefs 值不合法时,忽略已有状态并继续 Step 2。不要删除不匹配 runtime 文件,避免误伤其他窗口。
66
68
 
@@ -212,7 +214,6 @@ route_decision:
212
214
  mode: <inline | subagent | check-all-inline | check-all-subagent | check-inline | check-subagent>
213
215
  source: <trellis-route | route-prefs | numbered-fallback>
214
216
  scope: task
215
- task: <task.py current 的任务路径或 current>
216
217
 
217
218
  接下来主 agent 应当:
218
219
  - <路由表里对应的工具调用形式>
@@ -222,7 +223,7 @@ route_decision:
222
223
  - <要避免的工具调用>
223
224
  ```
224
225
 
225
- 中括号内行为条件性出现:仅命中个人配置时显示配置行;仅命中 runtime state 时显示“来自”行;写入 runtime state 成功时显示“已写入”行;仅轻量 check 时显示隐藏逃生口说明;仅 implement subagent + skip_compile=true 时附加“跳过编译”段。`route_decision` 必须保留在回复中;compact summary 若只有自然语言描述,后续 agent 仍应优先读取 runtime state,而不是把 summary 当证据。
226
+ 中括号内行为条件性出现:仅命中个人配置时显示配置行;仅命中 runtime state 时显示“来自”行;写入 runtime state 成功时显示“已写入”行;仅轻量 check 时显示隐藏逃生口说明;仅 implement subagent + skip_compile=true 时附加“跳过编译”段。`route_decision` 必须保留在回复中,但默认只保留 target/mode/source/scope;需要 task/path/decided_at 等诊断字段时重新调用 helper 并加 `--verbose`。compact summary 若只有自然语言描述,后续 agent 仍应优先读取 runtime state,而不是把 summary 当证据。
226
227
 
227
228
  ---
228
229
 
@@ -73,6 +73,21 @@ def _print(data: dict[str, Any]) -> int:
73
73
  return 0
74
74
 
75
75
 
76
+ def _output(args: argparse.Namespace, data: dict[str, Any], verbose: dict[str, Any] | None = None) -> int:
77
+ """按默认精简模式或详细模式输出 JSON。"""
78
+ if getattr(args, "verbose", False) and verbose:
79
+ data = {**data, **verbose}
80
+ return _print(data)
81
+
82
+
83
+ def _decision_summary(decision: dict[str, Any]) -> dict[str, Any]:
84
+ """提取默认输出需要的最小 route 决策字段。"""
85
+ return {
86
+ "mode": decision.get("mode"),
87
+ "source": decision.get("source"),
88
+ }
89
+
90
+
76
91
  def _current_task(repo_root: Path) -> tuple[str | None, str | None, str | None]:
77
92
  """通过 task.py current --source 获取当前任务和 session key。"""
78
93
  result = subprocess.run(
@@ -236,20 +251,27 @@ def read_runtime(args: argparse.Namespace) -> int:
236
251
  context = _read_json(path)
237
252
  decision = context.get("route_decisions", {}).get(args.target)
238
253
  if _valid_decision(decision, args.target, current_task):
239
- return _print(
254
+ return _output(
255
+ args,
240
256
  {
241
257
  "status": "hit",
258
+ **_decision_summary(decision),
259
+ },
260
+ {
261
+ "decision": decision,
242
262
  "path": _rel_path(repo_root, path),
243
263
  "context_key": context_key,
244
264
  "task": current_task,
245
- "decision": decision,
246
265
  }
247
266
  )
248
267
 
249
- return _print(
268
+ return _output(
269
+ args,
250
270
  {
251
271
  "status": "miss",
252
272
  "reason": "no-valid-decision",
273
+ },
274
+ {
253
275
  "path": _rel_path(repo_root, path),
254
276
  "context_key": context_key,
255
277
  "task": current_task,
@@ -272,14 +294,18 @@ def resolve_route(args: argparse.Namespace) -> int:
272
294
  context = _read_json(path)
273
295
  decision = context.get("route_decisions", {}).get(args.target)
274
296
  if _valid_decision(decision, args.target, current_task):
275
- return _print(
297
+ return _output(
298
+ args,
276
299
  {
277
300
  "status": "hit",
278
- "source": "runtime",
301
+ "origin": "runtime",
302
+ **_decision_summary(decision),
303
+ },
304
+ {
305
+ "decision": decision,
279
306
  "path": _rel_path(repo_root, path),
280
307
  "context_key": context_key,
281
308
  "task": current_task,
282
- "decision": decision,
283
309
  }
284
310
  )
285
311
 
@@ -294,23 +320,30 @@ def resolve_route(args: argparse.Namespace) -> int:
294
320
  pref_mode,
295
321
  "route-prefs",
296
322
  )
297
- return _print(
323
+ return _output(
324
+ args,
298
325
  {
299
326
  "status": "hit",
300
- "source": "route-prefs",
327
+ "origin": "route-prefs",
328
+ **_decision_summary(pref_decision),
329
+ },
330
+ {
331
+ "decision": pref_decision,
301
332
  "path": _rel_path(repo_root, written_path),
302
333
  "pref_path": _rel_path(repo_root, _pref_path(repo_root)),
303
334
  "context_key": context_key,
304
335
  "task": current_task,
305
- "decision": pref_decision,
306
336
  "wrote_runtime": True,
307
337
  }
308
338
  )
309
339
 
310
- return _print(
340
+ return _output(
341
+ args,
311
342
  {
312
343
  "status": "miss",
313
344
  "reason": "no-valid-decision-or-pref",
345
+ },
346
+ {
314
347
  "path": _rel_path(repo_root, path),
315
348
  "pref_path": _rel_path(repo_root, _pref_path(repo_root)),
316
349
  "context_key": context_key,
@@ -365,14 +398,18 @@ def write_route(args: argparse.Namespace) -> int:
365
398
  args.mode,
366
399
  args.source,
367
400
  )
368
- return _print(
401
+ return _output(
402
+ args,
369
403
  {
370
404
  "status": "written",
405
+ **_decision_summary(decision),
406
+ },
407
+ {
408
+ "decision": decision,
371
409
  "path": _rel_path(repo_root, path),
372
410
  "pref_path": _rel_path(repo_root, _pref_path(repo_root)) if args.save_pref else None,
373
411
  "context_key": context_key,
374
412
  "task": current_task,
375
- "decision": decision,
376
413
  "saved_pref": bool(args.save_pref),
377
414
  }
378
415
  )
@@ -387,10 +424,13 @@ def clear_pref(args: argparse.Namespace) -> int:
387
424
  existed = args.target in prefs
388
425
  prefs.pop(args.target, None)
389
426
  _write_prefs(repo_root, prefs)
390
- return _print(
427
+ return _output(
428
+ args,
391
429
  {
392
430
  "status": "cleared",
393
431
  "target": args.target,
432
+ },
433
+ {
394
434
  "existed": existed,
395
435
  "pref_path": _rel_path(repo_root, _pref_path(repo_root)),
396
436
  }
@@ -404,10 +444,12 @@ def build_parser() -> argparse.ArgumentParser:
404
444
 
405
445
  resolve_parser = subparsers.add_parser("resolve", help="resolve route from runtime then prefs")
406
446
  resolve_parser.add_argument("--target", choices=sorted(VALID_MODES), required=True)
447
+ resolve_parser.add_argument("--verbose", action="store_true", help="include diagnostic paths and session metadata")
407
448
  resolve_parser.set_defaults(func=resolve_route)
408
449
 
409
450
  read_parser = subparsers.add_parser("read-runtime", help="read a runtime route decision")
410
451
  read_parser.add_argument("--target", choices=sorted(VALID_MODES), required=True)
452
+ read_parser.add_argument("--verbose", action="store_true", help="include diagnostic paths and session metadata")
411
453
  read_parser.set_defaults(func=read_runtime)
412
454
 
413
455
  write_parser = subparsers.add_parser("write", help="write a route decision")
@@ -415,10 +457,12 @@ def build_parser() -> argparse.ArgumentParser:
415
457
  write_parser.add_argument("--mode", required=True)
416
458
  write_parser.add_argument("--source", choices=sorted(VALID_SOURCES), required=True)
417
459
  write_parser.add_argument("--save-pref", action="store_true")
460
+ write_parser.add_argument("--verbose", action="store_true", help="include diagnostic paths and session metadata")
418
461
  write_parser.set_defaults(func=write_route)
419
462
 
420
463
  clear_parser = subparsers.add_parser("clear-pref", help="clear a personal route preference")
421
464
  clear_parser.add_argument("--target", choices=sorted(PREF_MODES), required=True)
465
+ clear_parser.add_argument("--verbose", action="store_true", help="include diagnostic paths and preference metadata")
422
466
  clear_parser.set_defaults(func=clear_pref)
423
467
 
424
468
  return parser
@@ -1,7 +1,7 @@
1
1
  {
2
- "syncedAt": "2026-06-26T09:44:08.667Z",
2
+ "syncedAt": "2026-06-28T06:07:58.327Z",
3
3
  "syncedFrom": "vendor/skill-garden/.trellis",
4
- "sourceCommit": "031d74571ff336e44693d240700220f365f231db",
4
+ "sourceCommit": "57bac1361b3afe6ae3ea3fa456405bb888edab11",
5
5
  "variants": {
6
6
  "old": {
7
7
  "claudeSkills": [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flower-trellis",
3
- "version": "0.3.1-beta.6",
3
+ "version": "0.3.1",
4
4
  "description": "一键安装/升级 Trellis 并自动融合 skill-garden 强化包(默认 Claude + agents)",
5
5
  "type": "module",
6
6
  "bin": {