@caddis/cli 0.4.51 → 0.4.53

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 (100) hide show
  1. package/bundles/antigravity-plugin/CADDIS-GLOSSARY.md +1 -0
  2. package/bundles/antigravity-plugin/plugin.json +1 -1
  3. package/bundles/antigravity-plugin/repo_freshness.py +132 -5
  4. package/bundles/antigravity-plugin/scripts/caddis_checkout_guard.py +223 -0
  5. package/bundles/antigravity-plugin/scripts/caddis_docs_pr.py +284 -0
  6. package/bundles/antigravity-plugin/scripts/caddis_exit.py +2 -0
  7. package/bundles/antigravity-plugin/scripts/caddis_frontmatter.py +1 -0
  8. package/bundles/antigravity-plugin/scripts/caddis_gate.py +226 -195
  9. package/bundles/antigravity-plugin/scripts/caddis_glossary.py +3 -3
  10. package/bundles/antigravity-plugin/scripts/caddis_governor.py +48 -4
  11. package/bundles/antigravity-plugin/scripts/caddis_inventory.py +38 -0
  12. package/bundles/antigravity-plugin/scripts/caddis_lanes.py +294 -127
  13. package/bundles/antigravity-plugin/scripts/caddis_lineage_publish.py +458 -0
  14. package/bundles/antigravity-plugin/scripts/caddis_merge_chain.py +237 -0
  15. package/bundles/antigravity-plugin/scripts/caddis_notify.py +121 -0
  16. package/bundles/antigravity-plugin/scripts/caddis_prod_check.py +380 -0
  17. package/bundles/antigravity-plugin/scripts/caddis_redact.py +99 -0
  18. package/bundles/antigravity-plugin/scripts/caddis_relay_git.py +2 -2
  19. package/bundles/antigravity-plugin/scripts/caddis_review.py +1309 -0
  20. package/bundles/antigravity-plugin/scripts/caddis_roadmap.py +2056 -0
  21. package/bundles/antigravity-plugin/scripts/caddis_roadmap_run.py +2572 -0
  22. package/bundles/antigravity-plugin/scripts/caddis_routing.py +3 -2
  23. package/bundles/antigravity-plugin/scripts/caddis_rows.py +476 -0
  24. package/bundles/antigravity-plugin/scripts/caddis_spawn.py +8 -9
  25. package/bundles/antigravity-plugin/scripts/caddis_spend.py +415 -0
  26. package/bundles/antigravity-plugin/scripts/caddis_tidy.py +357 -20
  27. package/bundles/antigravity-plugin/scripts/caddis_todo.py +55 -0
  28. package/bundles/antigravity-plugin/scripts/caddis_workstreams.py +178 -19
  29. package/bundles/antigravity-plugin/scripts/caddis_worktree_close.py +349 -0
  30. package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +0 -56
  31. package/bundles/antigravity-plugin/scripts/claudster_doctor.py +1 -1
  32. package/bundles/antigravity-plugin/scripts/enforcement_inventory.py +0 -1
  33. package/bundles/antigravity-plugin/scripts/oss_review.py +2 -2
  34. package/bundles/antigravity-plugin/scripts/roadmap-recheck.ps1 +89 -0
  35. package/bundles/antigravity-plugin/scripts/roadmap-run.ps1 +88 -0
  36. package/bundles/antigravity-plugin/scripts/setup_project_ai.py +86 -2
  37. package/bundles/antigravity-plugin/session_end_agy.py +3 -3
  38. package/bundles/antigravity-plugin/skills/_registry.md +2 -6
  39. package/bundles/antigravity-plugin/skills/best-practices/agents/best-practices-referencer.md +1 -1
  40. package/bundles/antigravity-plugin/skills/best-practices/agents/codebase-context-builder.md +1 -1
  41. package/bundles/antigravity-plugin/skills/best-practices/agents/task-intent-analyzer.md +1 -1
  42. package/bundles/antigravity-plugin/skills/catchup/SKILL.md +7 -0
  43. package/bundles/antigravity-plugin/skills/cloud-phases/SKILL.md +1 -1
  44. package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +5 -2
  45. package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +29 -83
  46. package/bundles/antigravity-plugin/skills/handoff/SKILL.md +77 -48
  47. package/bundles/antigravity-plugin/skills/implement/SKILL.md +87 -147
  48. package/bundles/antigravity-plugin/skills/migrate-dir/SKILL.md +1 -1
  49. package/bundles/antigravity-plugin/skills/mmr/SKILL.md +5 -2
  50. package/bundles/antigravity-plugin/skills/office-documents-official/SKILL.md +24 -0
  51. package/bundles/antigravity-plugin/skills/park/SKILL.md +0 -1
  52. package/bundles/antigravity-plugin/skills/pr-merge/SKILL.md +8 -14
  53. package/bundles/antigravity-plugin/skills/prd/SKILL.md +2 -10
  54. package/bundles/antigravity-plugin/skills/roadmap/SKILL.md +259 -0
  55. package/bundles/antigravity-plugin/skills/roadmap/assets/plan-resume-prompt.md +77 -0
  56. package/bundles/antigravity-plugin/skills/roadmap/assets/render-check.template.mjs +68 -0
  57. package/bundles/antigravity-plugin/skills/roadmap/assets/review-protocol.md +78 -0
  58. package/bundles/antigravity-plugin/skills/roadmap/assets/roadmap.template.md +32 -0
  59. package/bundles/antigravity-plugin/skills/roadmap/assets/value-check.template.py +161 -0
  60. package/bundles/antigravity-plugin/skills/ship/SKILL.md +14 -14
  61. package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +6 -0
  62. package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +33 -14
  63. package/bundles/antigravity-plugin/skills/spawn-session/SKILL.md +4 -8
  64. package/bundles/antigravity-plugin/warm_start_agy.py +1 -3
  65. package/bundles/antigravity-plugin-extras/plugin.json +1 -1
  66. package/bundles/antigravity-plugin-extras/skills/_registry.md +1 -2
  67. package/bundles/antigravity-plugin-extras/skills/agent-orchestration/SKILL.md +5 -5
  68. package/bundles/antigravity-plugin-extras/skills/cross-review/SKILL.md +5 -2
  69. package/bundles/antigravity-plugin-extras/skills/runner-move/SKILL.md +214 -0
  70. package/bundles/codex/.codex/skills/docs/office-documents-official/SKILL.md +24 -0
  71. package/bundles/codex/.codex/skills/workflow/best-practices/agents/best-practices-referencer.md +1 -1
  72. package/bundles/codex/.codex/skills/workflow/best-practices/agents/codebase-context-builder.md +1 -1
  73. package/bundles/codex/.codex/skills/workflow/best-practices/agents/task-intent-analyzer.md +1 -1
  74. package/bundles/codex/.codex/skills/workflow/roadmap/SKILL.md +259 -0
  75. package/bundles/codex/.codex/skills/workflow/roadmap/assets/plan-resume-prompt.md +77 -0
  76. package/bundles/codex/.codex/skills/workflow/roadmap/assets/render-check.template.mjs +68 -0
  77. package/bundles/codex/.codex/skills/workflow/roadmap/assets/review-protocol.md +78 -0
  78. package/bundles/codex/.codex/skills/workflow/roadmap/assets/roadmap.template.md +32 -0
  79. package/bundles/codex/.codex/skills/workflow/roadmap/assets/value-check.template.py +161 -0
  80. package/bundles/codex/AGENTS.md +5 -4
  81. package/bundles/manifest.json +3 -3
  82. package/package.json +1 -1
  83. package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +0 -233
  84. package/bundles/antigravity-plugin/skills/advisory-hub/reference/context-template.md +0 -214
  85. package/bundles/antigravity-plugin/skills/advisory-hub/reference/hub-handbook.md +0 -233
  86. package/bundles/antigravity-plugin/skills/advisory-hub/reference/report-contract.md +0 -94
  87. package/bundles/antigravity-plugin/skills/advisory-hub/reference/succession.md +0 -118
  88. package/bundles/antigravity-plugin/skills/resume/SKILL.md +0 -6
  89. package/bundles/antigravity-plugin/skills/review/SKILL.md +0 -6
  90. package/bundles/antigravity-plugin/skills/spawn-hub/SKILL.md +0 -341
  91. package/bundles/antigravity-plugin/skills/statusline/SKILL.md +0 -6
  92. package/bundles/antigravity-plugin/skills/validate-phase/SKILL.md +0 -143
  93. package/bundles/antigravity-plugin-extras/skills/data-lineage/SKILL.md +0 -158
  94. package/bundles/antigravity-plugin-extras/skills/data-lineage/scripts/convert_doc_to_confluence.py +0 -1430
  95. package/bundles/antigravity-plugin-extras/skills/golden-plan/SKILL.md +0 -586
  96. package/bundles/codex/.codex/skills/workflow/advisory-hub/SKILL.md +0 -233
  97. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/context-template.md +0 -214
  98. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/hub-handbook.md +0 -233
  99. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/report-contract.md +0 -94
  100. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/succession.md +0 -118
@@ -0,0 +1,284 @@
1
+ """Write handoff's tracked doc edits in a temp worktree this session owns, then open one docs PR.
2
+
3
+ A shared checkout (see `caddis_checkout_guard.py shared`) may hold another session's uncommitted edits, so
4
+ handoff must not commit there. Instead:
5
+
6
+ caddis_docs_pr.py start --repo <root>
7
+ git fetch origin, then `git worktree add -b docs/handoff-<utc> <tmp> origin/<default>`;
8
+ prints `WORKTREE: <path>`. The worktree is new and belongs to this session only, so no other
9
+ session's edits can enter it.
10
+ caddis_docs_pr.py finish --worktree <path> --title T --body B
11
+ first stages every change in the worktree and saves the full diff (staged, unstaged and
12
+ untracked) to a new patch file. Then it commits, pushes, opens a PR with
13
+ `gh api repos/<owner>/<repo>/pulls`, prints `PR: <url>` and one `FILE: <path>` line per file.
14
+ With no change it prints `PR: none`. On any failure after the patch is saved it prints
15
+ `PATCH: <path>`. It removes the worktree and the local branch only after a PR opened, after the
16
+ patch was saved, or when there was no change. If the patch cannot be saved, it keeps the worktree
17
+ and prints `WORKTREE KEPT: <path>`. It never merges.
18
+
19
+ `finish` acts only on a linked worktree that `start` made: its git dir differs from the common git dir, it is
20
+ not the main worktree, it is under the temp folder, and its branch is `docs/handoff-<utc>[-n]`. Anything else
21
+ is refused (exit 4) and left as it is.
22
+
23
+ Exit codes (caddis_exit): 0 clean (PR opened, or no change), 1 blocked (the PR could not be opened),
24
+ 3 could not run (git or the push failed, no GitHub origin), 4 error (bad usage, not a docs-PR worktree).
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import argparse
30
+ import datetime
31
+ import json
32
+ import os
33
+ import re
34
+ import shutil
35
+ import subprocess
36
+ import sys
37
+ import tempfile
38
+ from pathlib import Path
39
+
40
+ try:
41
+ import caddis_exit
42
+ import caddis_checkout_guard
43
+ import caddis_roadmap as roadmap
44
+ except ModuleNotFoundError as exc:
45
+ if exc.name not in {"caddis_exit", "caddis_checkout_guard", "caddis_roadmap"}:
46
+ raise
47
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
48
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "claude-harness" / "scripts"))
49
+ import caddis_exit
50
+ import caddis_checkout_guard
51
+ import caddis_roadmap as roadmap
52
+
53
+ BRANCH_PREFIX = "docs/handoff-"
54
+ DIR_PREFIX = "caddis-docs-pr-"
55
+ BRANCH_RE = re.compile(r"^docs/handoff-\d{14}(?:-\d+)?$")
56
+
57
+
58
+ class DocsPrError(Exception):
59
+ def __init__(self, message: str, code: int):
60
+ super().__init__(message)
61
+ self.code = code
62
+
63
+
64
+ def _git(root: Path, *args: str, check: bool = True):
65
+ """git through caddis_roadmap: no credential prompt, and a timeout on fetch and push."""
66
+ return roadmap._git(Path(root), *args, check=check)
67
+
68
+
69
+ def _utc() -> str:
70
+ return datetime.datetime.now(datetime.timezone.utc).strftime("%Y%m%d%H%M%S")
71
+
72
+
73
+ def start(repo: Path, out=print) -> int:
74
+ repo = Path(repo).resolve()
75
+ base = roadmap.fetch(repo)
76
+ stamp = _utc()
77
+ tmp_root = Path(tempfile.gettempdir())
78
+ # Two starts in one second must not collide on the path or the branch.
79
+ suffix = ""
80
+ n = 1
81
+ while (tmp_root / f"{DIR_PREFIX}{stamp}{suffix}").exists() or \
82
+ _git(repo, "rev-parse", "--verify", "--quiet", f"refs/heads/{BRANCH_PREFIX}{stamp}{suffix}",
83
+ check=False).returncode == 0:
84
+ n += 1
85
+ suffix = f"-{n}"
86
+ worktree = tmp_root / f"{DIR_PREFIX}{stamp}{suffix}"
87
+ branch = f"{BRANCH_PREFIX}{stamp}{suffix}"
88
+ _git(repo, "worktree", "add", "--quiet", "-b", branch, str(worktree), f"origin/{base}")
89
+ out(f"WORKTREE: {worktree}")
90
+ return caddis_exit.CLEAN
91
+
92
+
93
+ def _abs(base: Path, raw: str) -> Path:
94
+ path = Path(raw.strip())
95
+ if not path.is_absolute():
96
+ path = base / path
97
+ return path.resolve()
98
+
99
+
100
+ def _main_repo(worktree: Path) -> Path:
101
+ """The main checkout: the first entry of `git worktree list --porcelain`."""
102
+ for line in _git(worktree, "worktree", "list", "--porcelain").stdout.splitlines():
103
+ if line.startswith("worktree "):
104
+ return Path(line[len("worktree "):]).resolve()
105
+ raise DocsPrError(f"git worktree list gave no main worktree for {worktree}", caddis_exit.ERROR)
106
+
107
+
108
+ def _is_under(path: Path, parent: Path) -> bool:
109
+ try:
110
+ path.relative_to(parent)
111
+ except ValueError:
112
+ return False
113
+ return path != parent
114
+
115
+
116
+ def _check_owned(worktree: Path) -> tuple[Path, str]:
117
+ """(main repo, branch) of a worktree `start` made; DocsPrError(ERROR) for anything else."""
118
+ if not worktree.is_dir():
119
+ raise DocsPrError(f"not a directory: {worktree}", caddis_exit.ERROR)
120
+ proc = _git(worktree, "rev-parse", "--show-toplevel", check=False)
121
+ if proc.returncode != 0:
122
+ raise DocsPrError(f"not a git worktree: {worktree}", caddis_exit.ERROR)
123
+ if Path(proc.stdout.strip()).resolve() != worktree.resolve():
124
+ raise DocsPrError(f"not the top of a worktree: {worktree}", caddis_exit.ERROR)
125
+ git_dir = _abs(worktree, _git(worktree, "rev-parse", "--git-dir").stdout)
126
+ common = _abs(worktree, _git(worktree, "rev-parse", "--git-common-dir").stdout)
127
+ if git_dir == common:
128
+ raise DocsPrError(f"{worktree} is not a linked worktree; nothing done", caddis_exit.ERROR)
129
+ main = _main_repo(worktree)
130
+ if main == worktree.resolve():
131
+ raise DocsPrError(f"{worktree} is the main checkout, not a docs-PR worktree; nothing done",
132
+ caddis_exit.ERROR)
133
+ branch = _git(worktree, "branch", "--show-current").stdout.strip()
134
+ if not BRANCH_RE.match(branch):
135
+ raise DocsPrError(f"{worktree} is on branch '{branch}', not a {BRANCH_PREFIX}<utc> branch; nothing done",
136
+ caddis_exit.ERROR)
137
+ resolved = worktree.resolve()
138
+ if resolved.parent != Path(tempfile.gettempdir()).resolve() or not resolved.name.startswith(DIR_PREFIX):
139
+ raise DocsPrError(f"{worktree} is not a {DIR_PREFIX}* folder directly in the temp folder that start uses; "
140
+ "nothing done", caddis_exit.ERROR)
141
+ return main, branch
142
+
143
+
144
+ def _changed_files(worktree: Path) -> list[str]:
145
+ """Every path in `git status --porcelain -z`, parsed on NUL, so spaces, ' -> ' and non-ASCII stay exact.
146
+
147
+ A rename or copy entry is followed by one more NUL field, the original path; both paths count.
148
+ """
149
+ proc = subprocess.run(["git", "-C", str(worktree), "status", "--porcelain=v1", "--untracked-files=all", "-z"],
150
+ capture_output=True, stdin=subprocess.DEVNULL)
151
+ if proc.returncode != 0:
152
+ raise DocsPrError(f"git status failed in {worktree}", caddis_exit.NOT_RUN)
153
+ parts = proc.stdout.decode("utf-8", errors="surrogateescape").split("\0")
154
+ files: list[str] = []
155
+ idx = 0
156
+ while idx < len(parts):
157
+ entry = parts[idx]
158
+ idx += 1
159
+ if len(entry) < 4:
160
+ continue
161
+ xy, paths = entry[:2], [entry[3:]]
162
+ if ("R" in xy or "C" in xy) and idx < len(parts):
163
+ paths.append(parts[idx])
164
+ idx += 1
165
+ for path in paths:
166
+ if path and path not in files:
167
+ files.append(path)
168
+ return files
169
+
170
+
171
+ def open_pr(gh_repo: str, branch: str, base: str, title: str, body: str) -> str:
172
+ """Open a PR with the REST API and return its URL. `gh` takes the account from GH_TOKEN when it is set."""
173
+ proc = roadmap.run_bounded(["gh", "api", f"repos/{gh_repo}/pulls", "-f", f"title={title}", "-f",
174
+ f"head={branch}", "-f", f"base={base}", "-f", f"body={body}"],
175
+ roadmap.GH_TIMEOUT, "gh api (open the PR)")
176
+ if proc.returncode != 0:
177
+ raise DocsPrError(f"could not open the PR: {(proc.stderr or proc.stdout).strip()[:300]}",
178
+ caddis_exit.BLOCKED)
179
+ try:
180
+ return str(json.loads(proc.stdout)["html_url"])
181
+ except (ValueError, KeyError, TypeError) as exc:
182
+ raise DocsPrError(f"gh api gave no PR URL: {exc}", caddis_exit.BLOCKED) from exc
183
+
184
+
185
+ def _save_patch(worktree: Path) -> Path:
186
+ """Stage every change and write the full staged diff to a new patch file (mkstemp: no predictable path).
187
+
188
+ `git add -A` is safe here: this worktree was made by `start` for this session only (see _check_owned).
189
+ """
190
+ _git(worktree, "add", "-A")
191
+ proc = subprocess.run(["git", "-C", str(worktree), "diff", "--cached", "--binary"],
192
+ capture_output=True, stdin=subprocess.DEVNULL)
193
+ if proc.returncode != 0:
194
+ raise DocsPrError(f"git diff failed in {worktree}", caddis_exit.NOT_RUN)
195
+ fd, name = tempfile.mkstemp(prefix=DIR_PREFIX, suffix=".patch")
196
+ with os.fdopen(fd, "wb") as handle:
197
+ handle.write(proc.stdout)
198
+ return Path(name)
199
+
200
+
201
+ def _remove(main: Path, worktree: Path, branch: str) -> None:
202
+ for args in (("worktree", "remove", "--force", "--force", str(worktree)), ("worktree", "prune"),
203
+ ("branch", "-D", branch)):
204
+ try:
205
+ _git(main, *args, check=False)
206
+ except (roadmap.RoadmapError, OSError):
207
+ pass
208
+ if worktree.exists():
209
+ shutil.rmtree(worktree, ignore_errors=True)
210
+
211
+
212
+ def finish(worktree: Path, title: str, body: str, out=print) -> int:
213
+ worktree = Path(worktree).resolve()
214
+ main, branch = _check_owned(worktree) # refuses before anything is changed or removed
215
+ # Save the session's edits FIRST. Until the patch exists, nothing may remove the worktree.
216
+ try:
217
+ files = _changed_files(worktree)
218
+ patch = _save_patch(worktree) if files else None
219
+ except (DocsPrError, roadmap.RoadmapError, OSError) as exc:
220
+ out(f"docs PR failed: could not save the change: {exc}")
221
+ out(f"WORKTREE KEPT: {worktree}")
222
+ return getattr(exc, "code", caddis_exit.NOT_RUN)
223
+ if patch is None:
224
+ _remove(main, worktree, branch)
225
+ out("PR: none")
226
+ return caddis_exit.CLEAN
227
+ pushed = False
228
+ try:
229
+ gh_repo = roadmap.gh_repo_of(main)
230
+ if gh_repo is None:
231
+ raise DocsPrError("origin is not a GitHub remote; cannot open a docs PR", caddis_exit.NOT_RUN)
232
+ base = roadmap.default_branch(main)
233
+ _git(worktree, "commit", "--quiet", "-m", title)
234
+ _git(worktree, "push", "--quiet", "-u", "origin", branch)
235
+ pushed = True
236
+ url = open_pr(gh_repo, branch, base, title, body)
237
+ except (DocsPrError, roadmap.RoadmapError, OSError) as exc:
238
+ out(f"docs PR failed: {exc}")
239
+ out(f"PATCH: {patch}")
240
+ if pushed:
241
+ try:
242
+ _git(main, "push", "--quiet", "origin", "--delete", branch, check=False)
243
+ except (roadmap.RoadmapError, OSError):
244
+ pass
245
+ _remove(main, worktree, branch)
246
+ return getattr(exc, "code", caddis_exit.NOT_RUN)
247
+ out(f"PR: {url}")
248
+ for path in files:
249
+ out(f"FILE: {path}")
250
+ _remove(main, worktree, branch)
251
+ try:
252
+ patch.unlink()
253
+ except OSError:
254
+ pass
255
+ return caddis_exit.CLEAN
256
+
257
+
258
+ def main(argv: list[str] | None = None) -> int:
259
+ parser = argparse.ArgumentParser(description="Handoff's docs PR from a temp worktree.")
260
+ sub = parser.add_subparsers(dest="command")
261
+ p_start = sub.add_parser("start", help="make the worktree from origin/<default>")
262
+ p_start.add_argument("--repo", required=True, type=Path)
263
+ p_finish = sub.add_parser("finish", help="save a patch, commit, push and open the PR, then remove the worktree")
264
+ p_finish.add_argument("--worktree", required=True, type=Path)
265
+ p_finish.add_argument("--title", required=True)
266
+ p_finish.add_argument("--body", required=True)
267
+ try:
268
+ args = parser.parse_args(argv)
269
+ except SystemExit:
270
+ return caddis_exit.ERROR
271
+ try:
272
+ if args.command == "start":
273
+ return start(args.repo)
274
+ if args.command == "finish":
275
+ return finish(args.worktree, args.title, args.body)
276
+ except (DocsPrError, roadmap.RoadmapError) as exc:
277
+ print(f"caddis_docs_pr: {exc}", file=sys.stderr)
278
+ return exc.code
279
+ parser.print_help(sys.stderr)
280
+ return caddis_exit.ERROR
281
+
282
+
283
+ if __name__ == "__main__":
284
+ sys.exit(main())
@@ -5,6 +5,7 @@ BLOCKED = 1
5
5
  ADVISORY = 2
6
6
  NOT_RUN = 3
7
7
  ERROR = 4
8
+ ROUND_LIMIT = 5 # caddis_review.py --plan: round limit reached, stop, the owner decides
8
9
 
9
10
  MEANING = {
10
11
  CLEAN: "clean",
@@ -12,4 +13,5 @@ MEANING = {
12
13
  ADVISORY: "advisory",
13
14
  NOT_RUN: "could not run",
14
15
  ERROR: "error or bad usage",
16
+ ROUND_LIMIT: "round limit reached, the owner decides",
15
17
  }
@@ -36,6 +36,7 @@ ALLOWED_TYPES: set[str] = {
36
36
  "hub-spawn",
37
37
  "advisory-context",
38
38
  "phase-prompt",
39
+ "open-work",
39
40
  }
40
41
 
41
42