tmux-agent 0.1.0

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 (161) hide show
  1. package/.codex/skills/speckit/SKILL.md +173 -0
  2. package/.codex/skills/speckit/assets/templates/checklist-template.md +49 -0
  3. package/.codex/skills/speckit/assets/templates/notes-entrypoints-template.md +11 -0
  4. package/.codex/skills/speckit/assets/templates/notes-questions-template.md +7 -0
  5. package/.codex/skills/speckit/assets/templates/notes-readme-template.md +36 -0
  6. package/.codex/skills/speckit/assets/templates/notes-session-template.md +21 -0
  7. package/.codex/skills/speckit/assets/templates/plan-template.md +126 -0
  8. package/.codex/skills/speckit/assets/templates/spec-template.md +135 -0
  9. package/.codex/skills/speckit/assets/templates/tasks-template.md +269 -0
  10. package/.codex/skills/speckit/references/acceptance.md +183 -0
  11. package/.codex/skills/speckit/references/analyze.md +186 -0
  12. package/.codex/skills/speckit/references/checklist.md +302 -0
  13. package/.codex/skills/speckit/references/clarify-auto.md +69 -0
  14. package/.codex/skills/speckit/references/clarify-detailed.md +78 -0
  15. package/.codex/skills/speckit/references/clarify.md +189 -0
  16. package/.codex/skills/speckit/references/constitution.md +90 -0
  17. package/.codex/skills/speckit/references/group.md +89 -0
  18. package/.codex/skills/speckit/references/implement-task.md +115 -0
  19. package/.codex/skills/speckit/references/implement.md +129 -0
  20. package/.codex/skills/speckit/references/notes.md +82 -0
  21. package/.codex/skills/speckit/references/plan-deep.md +87 -0
  22. package/.codex/skills/speckit/references/plan-from-questions.md +115 -0
  23. package/.codex/skills/speckit/references/plan-from-review.md +89 -0
  24. package/.codex/skills/speckit/references/plan.md +97 -0
  25. package/.codex/skills/speckit/references/review-plan.md +156 -0
  26. package/.codex/skills/speckit/references/specify.md +246 -0
  27. package/.codex/skills/speckit/references/tasks.md +155 -0
  28. package/.codex/skills/speckit/references/taskstoissues.md +33 -0
  29. package/.codex/skills/speckit/scripts/bash/check-prerequisites.sh +206 -0
  30. package/.codex/skills/speckit/scripts/bash/common.sh +191 -0
  31. package/.codex/skills/speckit/scripts/bash/create-new-feature.sh +259 -0
  32. package/.codex/skills/speckit/scripts/bash/extract-coded-points.sh +322 -0
  33. package/.codex/skills/speckit/scripts/bash/extract-spec-ids.sh +238 -0
  34. package/.codex/skills/speckit/scripts/bash/extract-tasks.sh +295 -0
  35. package/.codex/skills/speckit/scripts/bash/extract-user-stories.sh +312 -0
  36. package/.codex/skills/speckit/scripts/bash/setup-notes.sh +182 -0
  37. package/.codex/skills/speckit/scripts/bash/setup-plan.sh +110 -0
  38. package/.codex/skills/speckit/scripts/bash/show-todo-tasks.sh +257 -0
  39. package/.codex/skills/speckit/scripts/bash/spec-group-checklist.sh +402 -0
  40. package/.codex/skills/speckit/scripts/bash/spec-group-members.sh +215 -0
  41. package/.codex/skills/speckit/scripts/bash/spec-registry-graph.sh +399 -0
  42. package/.specify/memory/constitution.md +67 -0
  43. package/.specify/templates/agent-file-template.md +28 -0
  44. package/.specify/templates/checklist-template.md +49 -0
  45. package/.specify/templates/plan-template.md +126 -0
  46. package/.specify/templates/spec-template.md +135 -0
  47. package/.specify/templates/tasks-template.md +269 -0
  48. package/README.md +128 -0
  49. package/README.zh-CN.md +127 -0
  50. package/bun.lock +269 -0
  51. package/dist/cli/commands/codex/forkHome.js +88 -0
  52. package/dist/cli/commands/codex/send.js +55 -0
  53. package/dist/cli/commands/codex/sessionInfo.js +42 -0
  54. package/dist/cli/commands/codex/spawn.js +68 -0
  55. package/dist/cli/commands/find.js +26 -0
  56. package/dist/cli/commands/paneKill.js +33 -0
  57. package/dist/cli/commands/paneSpawn.js +40 -0
  58. package/dist/cli/commands/paneTitle.js +33 -0
  59. package/dist/cli/commands/read.js +34 -0
  60. package/dist/cli/commands/send.js +51 -0
  61. package/dist/cli/commands/snapshot.js +19 -0
  62. package/dist/cli/commands/ui/select.js +41 -0
  63. package/dist/cli/commands/windowKill.js +25 -0
  64. package/dist/cli/commands/windowLs.js +15 -0
  65. package/dist/cli/commands/windowNew.js +28 -0
  66. package/dist/cli/commands/windowRename.js +25 -0
  67. package/dist/cli/index.js +365 -0
  68. package/dist/cli/parse.js +39 -0
  69. package/dist/lib/codex/forkHome.js +101 -0
  70. package/dist/lib/codex/isCodexPane.js +55 -0
  71. package/dist/lib/codex/send.js +58 -0
  72. package/dist/lib/codex/sessionInfo.js +449 -0
  73. package/dist/lib/codex/spawn.js +246 -0
  74. package/dist/lib/contracts/types.js +2 -0
  75. package/dist/lib/fs/safeRm.js +32 -0
  76. package/dist/lib/io/readStdin.js +14 -0
  77. package/dist/lib/os/process.js +55 -0
  78. package/dist/lib/output/format.js +95 -0
  79. package/dist/lib/proc/lsof.js +42 -0
  80. package/dist/lib/proc/ps.js +60 -0
  81. package/dist/lib/targeting/errors.js +13 -0
  82. package/dist/lib/targeting/resolvePaneTarget.js +91 -0
  83. package/dist/lib/targeting/resolveWindowTarget.js +40 -0
  84. package/dist/lib/targeting/scope.js +58 -0
  85. package/dist/lib/tmux/capturePane.js +20 -0
  86. package/dist/lib/tmux/exec.js +66 -0
  87. package/dist/lib/tmux/paneOps.js +29 -0
  88. package/dist/lib/tmux/paste.js +23 -0
  89. package/dist/lib/tmux/sendKeys.js +47 -0
  90. package/dist/lib/tmux/session.js +29 -0
  91. package/dist/lib/tmux/snapshotPanes.js +46 -0
  92. package/dist/lib/tmux/snapshotWindows.js +24 -0
  93. package/dist/lib/tmux/windowOps.js +32 -0
  94. package/dist/lib/ui/popupSelect.js +432 -0
  95. package/dist/lib/ui/popupSupport.js +76 -0
  96. package/package.json +23 -0
  97. package/src/cli/commands/codex/forkHome.ts +141 -0
  98. package/src/cli/commands/codex/send.ts +83 -0
  99. package/src/cli/commands/codex/sessionInfo.ts +59 -0
  100. package/src/cli/commands/codex/spawn.ts +90 -0
  101. package/src/cli/commands/find.ts +40 -0
  102. package/src/cli/commands/paneKill.ts +49 -0
  103. package/src/cli/commands/paneSpawn.ts +53 -0
  104. package/src/cli/commands/paneTitle.ts +50 -0
  105. package/src/cli/commands/read.ts +48 -0
  106. package/src/cli/commands/send.ts +71 -0
  107. package/src/cli/commands/snapshot.ts +28 -0
  108. package/src/cli/commands/ui/select.ts +49 -0
  109. package/src/cli/commands/windowKill.ts +35 -0
  110. package/src/cli/commands/windowLs.ts +20 -0
  111. package/src/cli/commands/windowNew.ts +40 -0
  112. package/src/cli/commands/windowRename.ts +36 -0
  113. package/src/cli/index.ts +430 -0
  114. package/src/lib/codex/forkHome.ts +148 -0
  115. package/src/lib/codex/isCodexPane.ts +56 -0
  116. package/src/lib/codex/send.ts +84 -0
  117. package/src/lib/codex/sessionInfo.ts +521 -0
  118. package/src/lib/codex/spawn.ts +305 -0
  119. package/src/lib/contracts/types.ts +30 -0
  120. package/src/lib/fs/safeRm.ts +32 -0
  121. package/src/lib/io/readStdin.ts +11 -0
  122. package/src/lib/output/format.ts +105 -0
  123. package/src/lib/proc/lsof.ts +44 -0
  124. package/src/lib/proc/ps.ts +70 -0
  125. package/src/lib/targeting/errors.ts +25 -0
  126. package/src/lib/targeting/resolvePaneTarget.ts +106 -0
  127. package/src/lib/targeting/resolveWindowTarget.ts +45 -0
  128. package/src/lib/targeting/scope.ts +76 -0
  129. package/src/lib/tmux/capturePane.ts +21 -0
  130. package/src/lib/tmux/exec.ts +90 -0
  131. package/src/lib/tmux/paneOps.ts +35 -0
  132. package/src/lib/tmux/paste.ts +20 -0
  133. package/src/lib/tmux/sendKeys.ts +72 -0
  134. package/src/lib/tmux/session.ts +27 -0
  135. package/src/lib/tmux/snapshotPanes.ts +52 -0
  136. package/src/lib/tmux/snapshotWindows.ts +23 -0
  137. package/src/lib/tmux/windowOps.ts +43 -0
  138. package/src/lib/ui/popupSelect.ts +561 -0
  139. package/src/lib/ui/popupSupport.ts +84 -0
  140. package/tests/e2e/codexForkHome.test.ts +146 -0
  141. package/tests/e2e/codexSessionInfo.test.ts +112 -0
  142. package/tests/e2e/codexTuiSend.test.ts +68 -0
  143. package/tests/integration/codexSpawn.test.ts +113 -0
  144. package/tests/integration/paneOps.test.ts +60 -0
  145. package/tests/integration/sendRead.test.ts +52 -0
  146. package/tests/integration/snapshot.test.ts +39 -0
  147. package/tests/integration/tmuxHarness.ts +39 -0
  148. package/tests/integration/windowOps.test.ts +60 -0
  149. package/tests/unit/codexSend.test.ts +105 -0
  150. package/tests/unit/codexSessionInfo.test.ts +88 -0
  151. package/tests/unit/codexSpawn.test.ts +34 -0
  152. package/tests/unit/keys.test.ts +30 -0
  153. package/tests/unit/outputFormat.test.ts +52 -0
  154. package/tests/unit/popupSelect.test.ts +77 -0
  155. package/tests/unit/popupSupport.test.ts +109 -0
  156. package/tests/unit/resolvePaneTarget.test.ts +43 -0
  157. package/tests/unit/resolveWindowTarget.test.ts +36 -0
  158. package/tests/unit/safeRm.test.ts +41 -0
  159. package/tests/unit/scope.test.ts +57 -0
  160. package/tsconfig.json +14 -0
  161. package/vitest.config.ts +16 -0
@@ -0,0 +1,399 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Render a dependency graph from one or more spec-registry.json files.
4
+ #
5
+ # A "Spec Group" is any spec directory that contains `spec-registry.json`.
6
+ # You can pass group ids (e.g. 046) or registry file paths.
7
+ #
8
+ # Usage:
9
+ # spec-registry-graph.sh <group|registry.json>... [--all] [--focus <id>] [--direction upstream|downstream|both] [--format mermaid|text] [--json]
10
+ #
11
+ # Examples:
12
+ # spec-registry-graph.sh 046
13
+ # spec-registry-graph.sh 046 --focus 050
14
+ # spec-registry-graph.sh --all --focus 045 --direction downstream
15
+
16
+ set -euo pipefail
17
+
18
+ JSON_MODE=false
19
+ ALL=false
20
+ FOCUS=""
21
+ DIRECTION="both"
22
+ FORMAT="mermaid"
23
+ SOURCES=()
24
+
25
+ usage() {
26
+ cat << 'EOF'
27
+ Usage:
28
+ spec-registry-graph.sh <group|registry.json>... [--all] [--focus <id>] [--direction upstream|downstream|both] [--format mermaid|text] [--json]
29
+
30
+ Args:
31
+ <group|registry.json> Group spec id (e.g., 046 or 046-core-ng-roadmap) OR a direct path to spec-registry.json
32
+
33
+ Options:
34
+ --all Scan all `specs/*/spec-registry.json` and merge as one graph
35
+ --focus <id> Only render the dependency closure around this spec id (e.g. 045 / 045-xxx / specs/045-*/...)
36
+ --direction <dir> Closure direction for --focus: upstream | downstream | both (default: both)
37
+ --format <fmt> Output format: mermaid | text (default: mermaid). Ignored in --json mode.
38
+ --json Output machine JSON: nodes/edges/conflicts
39
+ --help, -h Show help
40
+
41
+ Notes:
42
+ - Edge direction: `A dependsOn B` renders as `B --> A` (B must be done before A).
43
+ - Nodes referenced in dependsOn but not defined in any loaded registry are shown as "external".
44
+ EOF
45
+ }
46
+
47
+ while [[ $# -gt 0 ]]; do
48
+ case "$1" in
49
+ --json)
50
+ JSON_MODE=true
51
+ shift
52
+ ;;
53
+ --all)
54
+ ALL=true
55
+ shift
56
+ ;;
57
+ --focus)
58
+ if [[ $# -lt 2 || "${2:-}" == --* ]]; then
59
+ echo "ERROR: --focus requires a value." >&2
60
+ exit 1
61
+ fi
62
+ FOCUS="$2"
63
+ shift 2
64
+ ;;
65
+ --direction)
66
+ if [[ $# -lt 2 || "${2:-}" == --* ]]; then
67
+ echo "ERROR: --direction requires a value." >&2
68
+ exit 1
69
+ fi
70
+ DIRECTION="$2"
71
+ shift 2
72
+ ;;
73
+ --format)
74
+ if [[ $# -lt 2 || "${2:-}" == --* ]]; then
75
+ echo "ERROR: --format requires a value." >&2
76
+ exit 1
77
+ fi
78
+ FORMAT="$2"
79
+ shift 2
80
+ ;;
81
+ --help|-h)
82
+ usage
83
+ exit 0
84
+ ;;
85
+ --*)
86
+ echo "ERROR: Unknown option '$1'. Use --help for usage information." >&2
87
+ exit 1
88
+ ;;
89
+ *)
90
+ SOURCES+=("$1")
91
+ shift
92
+ ;;
93
+ esac
94
+ done
95
+
96
+ if [[ "$ALL" != true && ${#SOURCES[@]} -eq 0 ]]; then
97
+ echo "ERROR: Provide at least one <group|registry.json>, or use --all." >&2
98
+ usage >&2
99
+ exit 1
100
+ fi
101
+
102
+ case "$DIRECTION" in
103
+ upstream|downstream|both) ;;
104
+ *)
105
+ echo "ERROR: Invalid --direction: $DIRECTION (use upstream|downstream|both)" >&2
106
+ exit 1
107
+ ;;
108
+ esac
109
+
110
+ case "$FORMAT" in
111
+ mermaid|text) ;;
112
+ *)
113
+ echo "ERROR: Invalid --format: $FORMAT (use mermaid|text)" >&2
114
+ exit 1
115
+ ;;
116
+ esac
117
+
118
+ SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
119
+ CHECK="$SCRIPT_DIR/check-prerequisites.sh"
120
+ source "$SCRIPT_DIR/common.sh"
121
+
122
+ repo_root="$(get_repo_root)"
123
+
124
+ REGISTRIES=()
125
+
126
+ if [[ "$ALL" == true ]]; then
127
+ shopt -s nullglob
128
+ for f in "$repo_root/specs"/*/spec-registry.json; do
129
+ REGISTRIES+=("$f")
130
+ done
131
+ shopt -u nullglob
132
+ fi
133
+
134
+ for s in "${SOURCES[@]}"; do
135
+ if [[ -f "$s" && "$s" == *.json ]]; then
136
+ REGISTRIES+=("$s")
137
+ continue
138
+ fi
139
+
140
+ paths_json="$("$CHECK" --json --paths-only --feature "$s")"
141
+ feature_dir="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["FEATURE_DIR"])' <<<"$paths_json")"
142
+ registry_json="$feature_dir/spec-registry.json"
143
+ if [[ ! -f "$registry_json" ]]; then
144
+ echo "ERROR: spec-registry.json not found for group '$s' at $registry_json" >&2
145
+ echo "Hint: add a machine-readable registry file (SSoT) under the group feature directory." >&2
146
+ exit 1
147
+ fi
148
+ REGISTRIES+=("$registry_json")
149
+ done
150
+
151
+ if [[ ${#REGISTRIES[@]} -eq 0 ]]; then
152
+ echo "ERROR: No registry files found." >&2
153
+ exit 1
154
+ fi
155
+
156
+ python3 - "$repo_root" "$JSON_MODE" "$FORMAT" "$FOCUS" "$DIRECTION" "${REGISTRIES[@]}" << 'PY'
157
+ from __future__ import annotations
158
+
159
+ import json
160
+ import re
161
+ import sys
162
+ from dataclasses import dataclass, field
163
+ from pathlib import Path
164
+ from typing import Any, Literal
165
+
166
+
167
+ Format = Literal["mermaid", "text"]
168
+ Direction = Literal["upstream", "downstream", "both"]
169
+
170
+
171
+ repo_root = Path(sys.argv[1])
172
+ json_mode = sys.argv[2].lower() == "true"
173
+ fmt: Format = sys.argv[3] # type: ignore[assignment]
174
+ focus_raw = sys.argv[4].strip()
175
+ direction: Direction = sys.argv[5] # type: ignore[assignment]
176
+ registry_files = [Path(p) for p in sys.argv[6:]]
177
+
178
+
179
+ def normalize_id(raw: str) -> str:
180
+ raw = raw.strip()
181
+ if raw.startswith("specs/"):
182
+ raw = raw[len("specs/") :]
183
+ raw = raw.strip().strip("/")
184
+
185
+ m = re.match(r"^(?P<prefix>\d{3})", raw)
186
+ return m.group("prefix") if m else raw
187
+
188
+
189
+ @dataclass
190
+ class Node:
191
+ id: str
192
+ defined: bool = False
193
+ dir: str | None = None
194
+ status: str | None = None
195
+ groups: set[str] = field(default_factory=set)
196
+
197
+
198
+ @dataclass(frozen=True)
199
+ class Edge:
200
+ dep: str
201
+ target: str
202
+
203
+
204
+ nodes: dict[str, Node] = {}
205
+ edges: set[Edge] = set()
206
+ conflicts: list[dict[str, Any]] = []
207
+
208
+
209
+ def get_node(node_id: str) -> Node:
210
+ if node_id not in nodes:
211
+ nodes[node_id] = Node(id=node_id)
212
+ return nodes[node_id]
213
+
214
+
215
+ def load_registry(path: Path) -> dict[str, Any]:
216
+ data = json.loads(path.read_text(encoding="utf-8", errors="replace"))
217
+ if not isinstance(data, dict):
218
+ raise ValueError(f"registry must be a JSON object: {path}")
219
+ return data
220
+
221
+
222
+ for registry_file in registry_files:
223
+ data = load_registry(registry_file)
224
+ group = str(data.get("group") or registry_file.parent.name)
225
+ entries = data.get("entries", [])
226
+ if not isinstance(entries, list):
227
+ raise ValueError(f"entries must be a list: {registry_file}")
228
+
229
+ for entry in entries:
230
+ if isinstance(entry, str):
231
+ entry_id = normalize_id(entry)
232
+ n = get_node(entry_id)
233
+ n.groups.add(group)
234
+ continue
235
+
236
+ if not isinstance(entry, dict):
237
+ continue
238
+
239
+ entry_id = normalize_id(str(entry.get("id") or entry.get("dir") or ""))
240
+ if not entry_id:
241
+ continue
242
+
243
+ entry_dir = entry.get("dir")
244
+ entry_status = entry.get("status")
245
+ entry_deps = entry.get("dependsOn", [])
246
+
247
+ if entry_deps is None:
248
+ entry_deps = []
249
+ if not isinstance(entry_deps, list):
250
+ entry_deps = []
251
+
252
+ n = get_node(entry_id)
253
+ n.groups.add(group)
254
+
255
+ if n.defined and (n.dir != entry_dir or n.status != entry_status):
256
+ conflicts.append(
257
+ {
258
+ "id": entry_id,
259
+ "existing": {"dir": n.dir, "status": n.status, "groups": sorted(n.groups)},
260
+ "incoming": {"dir": entry_dir, "status": entry_status, "group": group, "file": str(registry_file)},
261
+ }
262
+ )
263
+
264
+ if not n.defined:
265
+ n.defined = True
266
+ n.dir = str(entry_dir) if isinstance(entry_dir, str) else None
267
+ n.status = str(entry_status) if isinstance(entry_status, str) else None
268
+
269
+ for dep in entry_deps:
270
+ if dep is None:
271
+ continue
272
+ dep_id = normalize_id(str(dep))
273
+ if not dep_id:
274
+ continue
275
+ get_node(dep_id)
276
+ edges.add(Edge(dep=dep_id, target=entry_id))
277
+
278
+
279
+ def build_adj(edges_set: set[Edge]) -> tuple[dict[str, set[str]], dict[str, set[str]]]:
280
+ upstream: dict[str, set[str]] = {}
281
+ downstream: dict[str, set[str]] = {}
282
+ for e in edges_set:
283
+ upstream.setdefault(e.target, set()).add(e.dep)
284
+ downstream.setdefault(e.dep, set()).add(e.target)
285
+ return upstream, downstream
286
+
287
+
288
+ up, down = build_adj(edges)
289
+
290
+
291
+ def closure(start: str, *, direction: Direction) -> set[str]:
292
+ seen: set[str] = set()
293
+ queue: list[str] = [start]
294
+ while queue:
295
+ cur = queue.pop(0)
296
+ if cur in seen:
297
+ continue
298
+ seen.add(cur)
299
+ if direction in ("upstream", "both"):
300
+ for nxt in sorted(up.get(cur, set())):
301
+ if nxt not in seen:
302
+ queue.append(nxt)
303
+ if direction in ("downstream", "both"):
304
+ for nxt in sorted(down.get(cur, set())):
305
+ if nxt not in seen:
306
+ queue.append(nxt)
307
+ return seen
308
+
309
+
310
+ focus_id = normalize_id(focus_raw) if focus_raw else ""
311
+ if focus_id:
312
+ keep = closure(focus_id, direction=direction)
313
+ nodes = {k: v for k, v in nodes.items() if k in keep}
314
+ edges = {e for e in edges if e.dep in keep and e.target in keep}
315
+
316
+
317
+ def mermaid_id(spec_id: str) -> str:
318
+ # Mermaid node ids should be identifiers; we prefix with "S" and keep digits.
319
+ safe = re.sub(r"[^0-9A-Za-z_]", "_", spec_id)
320
+ if not safe:
321
+ safe = "unknown"
322
+ if safe[0].isdigit():
323
+ safe = "S" + safe
324
+ return safe
325
+
326
+
327
+ def sort_key(n: Node) -> tuple[int, str]:
328
+ # Prefer numeric ids first.
329
+ m = re.match(r"^(\d{3})$", n.id)
330
+ if m:
331
+ return (0, m.group(1))
332
+ return (1, n.id)
333
+
334
+
335
+ sorted_nodes = sorted(nodes.values(), key=sort_key)
336
+ sorted_edges = sorted(edges, key=lambda e: (e.dep, e.target))
337
+
338
+
339
+ if json_mode:
340
+ payload = {
341
+ "focus": focus_id or None,
342
+ "direction": direction,
343
+ "registries": [str(p) for p in registry_files],
344
+ "nodes": [
345
+ {
346
+ "id": n.id,
347
+ "defined": n.defined,
348
+ "dir": n.dir,
349
+ "status": n.status,
350
+ "groups": sorted(n.groups),
351
+ }
352
+ for n in sorted_nodes
353
+ ],
354
+ "edges": [{"dep": e.dep, "target": e.target} for e in sorted_edges],
355
+ "conflicts": conflicts,
356
+ }
357
+ print(json.dumps(payload, ensure_ascii=False))
358
+ raise SystemExit(0)
359
+
360
+
361
+ if fmt == "text":
362
+ for n in sorted_nodes:
363
+ deps = sorted(up.get(n.id, set()))
364
+ status = n.status or ("external" if not n.defined else "")
365
+ deps_str = ",".join(deps) if deps else "-"
366
+ print(f"{n.id}\t{status}\tdependsOn:{deps_str}")
367
+ raise SystemExit(0)
368
+
369
+
370
+ # mermaid
371
+ print("graph TD")
372
+
373
+ for n in sorted_nodes:
374
+ mid = mermaid_id(n.id)
375
+ label = n.id
376
+ if n.status:
377
+ label = f"{label} · {n.status}"
378
+ elif not n.defined:
379
+ label = f"{label} · external"
380
+ # Use double quotes via Mermaid bracket syntax.
381
+ print(f' {mid}["{label}"]')
382
+
383
+ for e in sorted_edges:
384
+ a = mermaid_id(e.dep)
385
+ b = mermaid_id(e.target)
386
+ print(f" {a} --> {b}")
387
+
388
+ # style external nodes
389
+ externals = [n for n in sorted_nodes if not n.defined]
390
+ if externals:
391
+ print("")
392
+ print(" classDef external stroke-dasharray: 5 5;")
393
+ for n in externals:
394
+ print(f" class {mermaid_id(n.id)} external;")
395
+
396
+ if conflicts:
397
+ print("")
398
+ print(f"%% WARNING: registry conflicts detected: {len(conflicts)} (use --json to inspect)")
399
+ PY
@@ -0,0 +1,67 @@
1
+ # Project Constitution (Spec Kit)
2
+
3
+ > This file captures project-level hard constraints, governance, and quality gates. Customize it for your project. If it conflicts with reality, treat this file as the source of truth and update templates and workflows accordingly.
4
+
5
+ ## I. Parallel Development Safety (Non-Negotiable)
6
+
7
+ - Assume the working tree may contain unrelated, uncommitted changes from other parallel tasks.
8
+ - Prohibit destructive Git commands unless explicitly requested by the user:
9
+ - `git restore` / `git checkout -- <path>` / `git reset` / `git clean` / `git stash`
10
+ - Do not run VCS write operations unless explicitly requested by the user:
11
+ - `git add` / `git commit` / `git push` / `git rebase` / `git merge` / `git cherry-pick`
12
+ - Use read-only commands for inspection (e.g., `git status` / `git diff`).
13
+
14
+ ## II. Spec-Driven Artifact Boundaries (`.specify/` + `specs/`)
15
+
16
+ - Feature directory: `specs/<NNN-*>/`
17
+ - `spec.md`: requirements and success criteria (WHAT/WHY). Avoid implementation details (HOW).
18
+ - `plan.md`: implementation approach and landing spots (HOW), including key decisions, risks, and validation strategy.
19
+ - `tasks.md`: executable task breakdown (dependencies/order/parallel markers). Check items off during implementation.
20
+ - If there is conflict or ambiguity: fix `spec.md` / `plan.md` first, then change code, to avoid spec/implementation drift.
21
+
22
+ ## II.a CLI Context Compatibility (Tmux In/Out)
23
+
24
+ - CLI commands SHOULD be usable both inside and outside tmux.
25
+ - If a command depends on an attached tmux client or “inside tmux” context (e.g., current client defaults, `display-popup`):
26
+ - It MUST detect the required context and refuse to run when the context is missing.
27
+ - It MUST provide an actionable error (how to supply an explicit target like `--session`, or run inside tmux).
28
+ - Default targeting rules MUST be explicit, deterministic, and overridable (avoid silent fallbacks that can cause mis-targeting).
29
+
30
+ ## II.b LLM-Friendly CLI Output Contract (Non-Negotiable)
31
+
32
+ - stdout MUST be consumable by automation (humans/LLMs/shell pipelines):
33
+ - If `--json` is supported, it MUST output single-line JSON to stdout and nothing else.
34
+ - Explanatory text and debug output MUST NOT be mixed into stdout (use stderr).
35
+ - Errors MUST be actionable:
36
+ - stderr MUST start with `Error:` for user-visible failures.
37
+ - Exit code MUST be non-zero on failure.
38
+ - Tracebacks/stacks MUST NOT be printed for expected user errors.
39
+ - IDs MUST be native and stable:
40
+ - Do not invent synthetic identifiers; prefer tmux native IDs (pane/window ids) with indexes only as convenience within a defined scope.
41
+ - Any write action MUST resolve and lock the stable native ID before performing side effects; ambiguity MUST fail with zero side effects.
42
+
43
+ ## III. Quality Gates (Must Be Explicit and Executed Before Shipping)
44
+
45
+ - Each feature must state which gates will be run and what counts as “pass” in `plan.md` (project-specific):
46
+ - typecheck / lint / test / build / e2e / contract tests
47
+ - For high-risk changes (security, data consistency, payments, permissions, etc.): include regression validation and a clear failure mitigation/rollback strategy.
48
+
49
+ ## IV. Performance & Observability (Enforced When Applicable)
50
+
51
+ - If this feature touches performance-sensitive paths or external performance boundaries: define budgets and a baseline in `plan.md`, and record reproducible evidence under `specs/<id>/perf/`.
52
+ - Key flows must have diagnosable signals (logs/metrics/traces or equivalent events), including:
53
+ - Correlation identifiers (requestId/sessionId/entityId, etc.)
54
+ - PII/sensitive data policy
55
+ - Toggles and cost model (overhead when enabled/disabled)
56
+
57
+ ## V. Breaking Changes Policy (Must Choose Explicitly)
58
+
59
+ > Define whether breaking changes are allowed and how migrations are handled.
60
+
61
+ - Policy: `semver`
62
+ - If introducing a breaking change: include migration steps and a blast radius checklist in `plan.md` and the PR/change notes.
63
+
64
+ ## VI. Template Locations (Optional)
65
+
66
+ - Default templates: `.specify/templates/*`
67
+ - If you want `$speckit` to be self-contained within the repo: mirror a copy into `.codex/skills/speckit/assets/templates/*` (keep them updated together to avoid drift).
@@ -0,0 +1,28 @@
1
+ # [PROJECT NAME] Development Guidelines
2
+
3
+ Auto-generated from all feature plans. Last updated: [DATE]
4
+
5
+ ## Active Technologies
6
+
7
+ [EXTRACTED FROM ALL PLAN.MD FILES]
8
+
9
+ ## Project Structure
10
+
11
+ ```text
12
+ [ACTUAL STRUCTURE FROM PLANS]
13
+ ```
14
+
15
+ ## Commands
16
+
17
+ [ONLY COMMANDS FOR ACTIVE TECHNOLOGIES]
18
+
19
+ ## Code Style
20
+
21
+ [LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE]
22
+
23
+ ## Recent Changes
24
+
25
+ [LAST 3 FEATURES AND WHAT THEY ADDED]
26
+
27
+ <!-- MANUAL ADDITIONS START -->
28
+ <!-- MANUAL ADDITIONS END -->
@@ -0,0 +1,49 @@
1
+ # [CHECKLIST TYPE] Checklist: [FEATURE NAME]
2
+
3
+ **Purpose**: [Brief description of what this checklist covers]
4
+ **Created**: [DATE]
5
+ **Feature**: [Link to spec.md or relevant documentation]
6
+
7
+ **Note**: This checklist is generated by the `$speckit checklist` stage based on feature context and requirements.
8
+
9
+ <!--
10
+ ============================================================================
11
+ IMPORTANT: The checklist items below are SAMPLE ITEMS for illustration only.
12
+
13
+ The $speckit checklist stage MUST replace these with actual items based on:
14
+ - User's specific checklist request
15
+ - Feature requirements from spec.md
16
+ - Technical context from plan.md
17
+ - Implementation details from tasks.md
18
+
19
+ DO NOT keep these sample items in the generated checklist file.
20
+ ============================================================================
21
+ -->
22
+
23
+ ## [Category 1]
24
+
25
+ - [ ] CHK001 First checklist item with clear action
26
+ - [ ] CHK002 Second checklist item
27
+ - [ ] CHK003 Third checklist item
28
+
29
+ ## [Category 2]
30
+
31
+ - [ ] CHK004 Another category item
32
+ - [ ] CHK005 Item with specific criteria
33
+ - [ ] CHK006 Final item in this category
34
+
35
+ ## Performance & Observability _(if applicable)_
36
+
37
+ - [ ] CHK0XX Performance budget + baseline measurement recorded (env/tool documented)
38
+ - [ ] CHK0XX No critical regression (or justified in Complexity Tracking)
39
+ - [ ] CHK0XX Logs/metrics/traces updated for key flows; PII/overhead reviewed
40
+ - [ ] CHK0XX Diagnostics include stable identifiers to correlate requests/sessions/entities
41
+ - [ ] CHK0XX Data consistency boundaries documented (transaction/atomicity/ordering as applicable)
42
+ - [ ] CHK0XX Breaking change declared and migration note linked (per project policy)
43
+
44
+ ## Notes
45
+
46
+ - Check items off as completed: `[x]`
47
+ - Add comments or findings inline
48
+ - Link to relevant resources or documentation
49
+ - Items are numbered sequentially for easy reference
@@ -0,0 +1,126 @@
1
+ # Implementation Plan: [FEATURE]
2
+
3
+ **Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link]
4
+ **Input**: Feature specification from `/specs/[###-feature-name]/spec.md`
5
+
6
+ **Note**: This template is copied into `specs/[###-feature-name]/plan.md` by the
7
+ Speckit plan workflow (`setup-plan.sh`).
8
+
9
+ ## Summary
10
+
11
+ [Extract from feature spec: primary requirement + technical approach from research]
12
+
13
+ ## Technical Context
14
+
15
+ <!--
16
+ ACTION REQUIRED: Replace the content in this section with the technical details
17
+ for the project. The structure here is presented in advisory capacity to guide
18
+ the iteration process.
19
+ -->
20
+
21
+ **Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
22
+ **Primary Dependencies**: [e.g., React, Next.js, FastAPI, Postgres, Redis or NEEDS CLARIFICATION]
23
+ **Storage**: [if applicable, e.g., files / N/A]
24
+ **Testing**: [e.g., Vitest, Jest, Pytest, Go test or NEEDS CLARIFICATION]
25
+ **Target Platform**: [e.g., Node.js 20+, browsers, iOS/Android]
26
+ **Project Type**: [single repo / monorepo / packages + apps]
27
+ **Performance Goals**: [budgets + measurement method (benchmark/profile) or NEEDS CLARIFICATION]
28
+ **Constraints**: [include diagnostics overhead budgets if applicable]
29
+ **Scale/Scope**: [domain-specific, e.g., 10k users, 1M LOC, 50 screens or NEEDS CLARIFICATION]
30
+
31
+ ## Constitution Check
32
+
33
+ _GATE: Must pass before implementation. Re-check after Phase 1 design._
34
+
35
+ - Answer the following BEFORE starting implementation, and re-check after Phase 1:
36
+ - What user value is delivered, and how is it validated (acceptance scenarios / SC-*)?
37
+ - What public/external surfaces change (API/CLI/UI/config), and what is the compatibility policy?
38
+ - What docs/specs must be updated first (docs-first where applicable) to avoid drift?
39
+ - What are the key risks (security, data loss, privacy, performance) and mitigations?
40
+ - If performance-sensitive: what budgets/baselines exist, and how are regressions prevented?
41
+ - What diagnostics/observability signals are required for triage (logs/metrics/traces)?
42
+ - What quality gates will be run before merge (typecheck / lint / test / build), and what counts as “pass”?
43
+
44
+ ## Perf Evidence Plan (IF APPLICABLE)
45
+
46
+ > If this feature touches performance-sensitive paths or external performance boundaries: this section must be filled. Otherwise mark it as `N/A`.
47
+
48
+ - Baseline semantics: before/after code change OR A/B strategy (choose one)
49
+ - envId: <os-arch.cpu.runtime-version>
50
+ - tool: <benchmark/profile tool name>
51
+ - collect (before): `specs/<id>/perf/before.<envId>.<tag>.<ext>`
52
+ - collect (after): `specs/<id>/perf/after.<envId>.<tag>.<ext>`
53
+ - diff: `specs/<id>/perf/diff.before__after.<ext>` (if applicable)
54
+ - Failure policy: if results are not comparable (env/tool changes, insufficient sample size, high variance) → re-run or narrow the scope; do not draw hard conclusions when not comparable.
55
+
56
+ ## Project Structure
57
+
58
+ ### Documentation (this feature)
59
+
60
+ ```text
61
+ specs/[###-feature]/
62
+ ├── plan.md # This file ($speckit plan output)
63
+ ├── research.md # Phase 0 output ($speckit plan)
64
+ ├── data-model.md # Phase 1 output ($speckit plan)
65
+ ├── quickstart.md # Phase 1 output ($speckit plan)
66
+ ├── contracts/ # Phase 1 output ($speckit plan)
67
+ ├── notes/ # Optional: handoff notes / entry points ($speckit notes)
68
+ └── tasks.md # Phase 2 output ($speckit tasks - NOT created by $speckit plan)
69
+ ```
70
+
71
+ ### Source Code (repository root)
72
+
73
+ <!--
74
+ ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
75
+ for this feature. Delete unused options and expand the chosen structure with
76
+ real paths (e.g., apps/admin, packages/something). The delivered plan must
77
+ not include Option labels.
78
+ -->
79
+
80
+ ```text
81
+ # [REMOVE IF UNUSED] Option 1: Single project (DEFAULT)
82
+ src/
83
+ ├── models/
84
+ ├── services/
85
+ ├── cli/
86
+ └── lib/
87
+
88
+ tests/
89
+ ├── contract/
90
+ ├── integration/
91
+ └── unit/
92
+
93
+ # [REMOVE IF UNUSED] Option 2: Web application (when "frontend" + "backend" detected)
94
+ backend/
95
+ ├── src/
96
+ │ ├── models/
97
+ │ ├── services/
98
+ │ └── api/
99
+ └── tests/
100
+
101
+ frontend/
102
+ ├── src/
103
+ │ ├── components/
104
+ │ ├── pages/
105
+ │ └── services/
106
+ └── tests/
107
+
108
+ # [REMOVE IF UNUSED] Option 3: Mobile + API (when "iOS/Android" detected)
109
+ api/
110
+ └── [same as backend above]
111
+
112
+ ios/ or android/
113
+ └── [platform-specific structure: feature modules, UI flows, platform tests]
114
+ ```
115
+
116
+ **Structure Decision**: [Document the selected structure and reference the real
117
+ directories captured above]
118
+
119
+ ## Complexity Tracking
120
+
121
+ > **Fill ONLY if Constitution Check has violations that must be justified**
122
+
123
+ | Violation | Why Needed | Simpler Alternative Rejected Because |
124
+ | -------------------------- | ------------------ | ------------------------------------ |
125
+ | [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
126
+ | [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |