@aipper/aiws-spec 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +12 -0
  2. package/docs/cli-interface.md +288 -0
  3. package/docs/spec-contract.md +183 -0
  4. package/package.json +18 -0
  5. package/templates/workspace/.agents/skills/aiws-change-archive/SKILL.md +23 -0
  6. package/templates/workspace/.agents/skills/aiws-change-list/SKILL.md +18 -0
  7. package/templates/workspace/.agents/skills/aiws-change-new/SKILL.md +26 -0
  8. package/templates/workspace/.agents/skills/aiws-change-next/SKILL.md +19 -0
  9. package/templates/workspace/.agents/skills/aiws-change-start/SKILL.md +27 -0
  10. package/templates/workspace/.agents/skills/aiws-change-status/SKILL.md +19 -0
  11. package/templates/workspace/.agents/skills/aiws-change-sync/SKILL.md +19 -0
  12. package/templates/workspace/.agents/skills/aiws-change-templates-init/SKILL.md +18 -0
  13. package/templates/workspace/.agents/skills/aiws-change-templates-which/SKILL.md +18 -0
  14. package/templates/workspace/.agents/skills/aiws-change-validate/SKILL.md +23 -0
  15. package/templates/workspace/.agents/skills/aiws-hooks-install/SKILL.md +30 -0
  16. package/templates/workspace/.agents/skills/aiws-hooks-status/SKILL.md +18 -0
  17. package/templates/workspace/.agents/skills/aiws-init/SKILL.md +27 -0
  18. package/templates/workspace/.agents/skills/aiws-rollback/SKILL.md +18 -0
  19. package/templates/workspace/.agents/skills/aiws-update/SKILL.md +26 -0
  20. package/templates/workspace/.agents/skills/aiws-validate/SKILL.md +22 -0
  21. package/templates/workspace/.agents/skills/ws-analyze/SKILL.md +26 -0
  22. package/templates/workspace/.agents/skills/ws-commit/SKILL.md +50 -0
  23. package/templates/workspace/.agents/skills/ws-dev/SKILL.md +34 -0
  24. package/templates/workspace/.agents/skills/ws-migrate/SKILL.md +54 -0
  25. package/templates/workspace/.agents/skills/ws-plan/SKILL.md +39 -0
  26. package/templates/workspace/.agents/skills/ws-preflight/SKILL.md +29 -0
  27. package/templates/workspace/.agents/skills/ws-req-change/SKILL.md +33 -0
  28. package/templates/workspace/.agents/skills/ws-req-contract-sync/SKILL.md +17 -0
  29. package/templates/workspace/.agents/skills/ws-req-contract-validate/SKILL.md +12 -0
  30. package/templates/workspace/.agents/skills/ws-req-flow-sync/SKILL.md +28 -0
  31. package/templates/workspace/.agents/skills/ws-req-review/SKILL.md +32 -0
  32. package/templates/workspace/.agents/skills/ws-review/SKILL.md +24 -0
  33. package/templates/workspace/.agents/skills/ws-rule/SKILL.md +23 -0
  34. package/templates/workspace/.aiws/manifest.json +36 -0
  35. package/templates/workspace/.claude/commands/aiws-init.md +19 -0
  36. package/templates/workspace/.claude/commands/aiws-rollback.md +12 -0
  37. package/templates/workspace/.claude/commands/aiws-update.md +18 -0
  38. package/templates/workspace/.claude/commands/aiws-validate.md +13 -0
  39. package/templates/workspace/.claude/commands/ws-analyze.md +27 -0
  40. package/templates/workspace/.claude/commands/ws-dev.md +24 -0
  41. package/templates/workspace/.claude/commands/ws-migrate.md +22 -0
  42. package/templates/workspace/.claude/commands/ws-preflight.md +27 -0
  43. package/templates/workspace/.claude/commands/ws-req-change.md +34 -0
  44. package/templates/workspace/.claude/commands/ws-req-contract-sync.md +18 -0
  45. package/templates/workspace/.claude/commands/ws-req-contract-validate.md +13 -0
  46. package/templates/workspace/.claude/commands/ws-req-flow-sync.md +20 -0
  47. package/templates/workspace/.claude/commands/ws-req-review.md +33 -0
  48. package/templates/workspace/.claude/commands/ws-review.md +25 -0
  49. package/templates/workspace/.claude/commands/ws-rule.md +24 -0
  50. package/templates/workspace/.codex/prompts/aiws-init.md +23 -0
  51. package/templates/workspace/.codex/prompts/aiws-rollback.md +16 -0
  52. package/templates/workspace/.codex/prompts/aiws-update.md +22 -0
  53. package/templates/workspace/.codex/prompts/aiws-validate.md +17 -0
  54. package/templates/workspace/.codex/prompts/ws-analyze.md +32 -0
  55. package/templates/workspace/.codex/prompts/ws-dev.md +29 -0
  56. package/templates/workspace/.codex/prompts/ws-migrate.md +27 -0
  57. package/templates/workspace/.codex/prompts/ws-preflight.md +32 -0
  58. package/templates/workspace/.codex/prompts/ws-req-change.md +39 -0
  59. package/templates/workspace/.codex/prompts/ws-req-contract-sync.md +23 -0
  60. package/templates/workspace/.codex/prompts/ws-req-contract-validate.md +18 -0
  61. package/templates/workspace/.codex/prompts/ws-req-flow-sync.md +25 -0
  62. package/templates/workspace/.codex/prompts/ws-req-review.md +38 -0
  63. package/templates/workspace/.codex/prompts/ws-review.md +30 -0
  64. package/templates/workspace/.codex/prompts/ws-rule.md +29 -0
  65. package/templates/workspace/.githooks/pre-commit +32 -0
  66. package/templates/workspace/.githooks/pre-push +32 -0
  67. package/templates/workspace/.iflow/agents/feature-reviewer.md +27 -0
  68. package/templates/workspace/.iflow/agents/requirements-analyst.md +24 -0
  69. package/templates/workspace/.iflow/agents/server-commit-manager.md +28 -0
  70. package/templates/workspace/.iflow/agents/server-fix-implementer.md +31 -0
  71. package/templates/workspace/.iflow/agents/server-test-planner.md +28 -0
  72. package/templates/workspace/.iflow/agents/server-test-triager.md +30 -0
  73. package/templates/workspace/.iflow/commands/aiws-init.toml +24 -0
  74. package/templates/workspace/.iflow/commands/aiws-rollback.toml +18 -0
  75. package/templates/workspace/.iflow/commands/aiws-update.toml +23 -0
  76. package/templates/workspace/.iflow/commands/aiws-validate.toml +18 -0
  77. package/templates/workspace/.iflow/commands/server-commit.toml +27 -0
  78. package/templates/workspace/.iflow/commands/server-drain.toml +99 -0
  79. package/templates/workspace/.iflow/commands/server-fix-and-commit.toml +27 -0
  80. package/templates/workspace/.iflow/commands/server-fix.toml +65 -0
  81. package/templates/workspace/.iflow/commands/server-test-plan.toml +62 -0
  82. package/templates/workspace/.iflow/commands/server-test.toml +58 -0
  83. package/templates/workspace/.iflow/commands/server-triage.toml +38 -0
  84. package/templates/workspace/.iflow/commands/server_test-plan.toml +12 -0
  85. package/templates/workspace/.iflow/commands/server_test.toml +12 -0
  86. package/templates/workspace/.iflow/commands/ws-analyze.toml +33 -0
  87. package/templates/workspace/.iflow/commands/ws-contract-check.toml +69 -0
  88. package/templates/workspace/.iflow/commands/ws-dev.toml +34 -0
  89. package/templates/workspace/.iflow/commands/ws-doctor.toml +141 -0
  90. package/templates/workspace/.iflow/commands/ws-env-doctor.toml +74 -0
  91. package/templates/workspace/.iflow/commands/ws-feature-deliver.toml +44 -0
  92. package/templates/workspace/.iflow/commands/ws-feature-plan.toml +47 -0
  93. package/templates/workspace/.iflow/commands/ws-init.toml +53 -0
  94. package/templates/workspace/.iflow/commands/ws-memory-bank-init.toml +100 -0
  95. package/templates/workspace/.iflow/commands/ws-migrate.toml +59 -0
  96. package/templates/workspace/.iflow/commands/ws-preflight.toml +30 -0
  97. package/templates/workspace/.iflow/commands/ws-req-change.toml +52 -0
  98. package/templates/workspace/.iflow/commands/ws-req-contract-sync.toml +25 -0
  99. package/templates/workspace/.iflow/commands/ws-req-contract-validate.toml +16 -0
  100. package/templates/workspace/.iflow/commands/ws-req-flow-sync.toml +36 -0
  101. package/templates/workspace/.iflow/commands/ws-req-review.toml +56 -0
  102. package/templates/workspace/.iflow/commands/ws-review.toml +32 -0
  103. package/templates/workspace/.iflow/commands/ws-rule.toml +43 -0
  104. package/templates/workspace/.opencode/command/aiws-init.md +19 -0
  105. package/templates/workspace/.opencode/command/aiws-rollback.md +12 -0
  106. package/templates/workspace/.opencode/command/aiws-update.md +18 -0
  107. package/templates/workspace/.opencode/command/aiws-validate.md +13 -0
  108. package/templates/workspace/.opencode/command/ws-analyze.md +27 -0
  109. package/templates/workspace/.opencode/command/ws-dev.md +24 -0
  110. package/templates/workspace/.opencode/command/ws-migrate.md +22 -0
  111. package/templates/workspace/.opencode/command/ws-preflight.md +27 -0
  112. package/templates/workspace/.opencode/command/ws-req-change.md +34 -0
  113. package/templates/workspace/.opencode/command/ws-req-contract-sync.md +18 -0
  114. package/templates/workspace/.opencode/command/ws-req-contract-validate.md +13 -0
  115. package/templates/workspace/.opencode/command/ws-req-flow-sync.md +20 -0
  116. package/templates/workspace/.opencode/command/ws-req-review.md +33 -0
  117. package/templates/workspace/.opencode/command/ws-review.md +25 -0
  118. package/templates/workspace/.opencode/command/ws-rule.md +24 -0
  119. package/templates/workspace/AGENTS.md +22 -0
  120. package/templates/workspace/AI_PROJECT.md +86 -0
  121. package/templates/workspace/AI_WORKSPACE.md +167 -0
  122. package/templates/workspace/REQUIREMENTS.md +94 -0
  123. package/templates/workspace/changes/README.md +55 -0
  124. package/templates/workspace/changes/templates/design.md +29 -0
  125. package/templates/workspace/changes/templates/proposal.md +59 -0
  126. package/templates/workspace/changes/templates/tasks.md +33 -0
  127. package/templates/workspace/issues/problem-issues.csv +2 -0
  128. package/templates/workspace/manifest.json +205 -0
  129. package/templates/workspace/memory-bank/README.md +14 -0
  130. package/templates/workspace/memory-bank/architecture.md +9 -0
  131. package/templates/workspace/memory-bank/implementation-plan.md +11 -0
  132. package/templates/workspace/memory-bank/progress.md +10 -0
  133. package/templates/workspace/memory-bank/tech-stack.md +11 -0
  134. package/templates/workspace/requirements/CHANGELOG.md +13 -0
  135. package/templates/workspace/requirements/requirements-issues.csv +2 -0
  136. package/templates/workspace/secrets/test-accounts.example.json +32 -0
  137. package/templates/workspace/tools/iflow_watchdog.sh +138 -0
  138. package/templates/workspace/tools/install_iflow_watchdog_systemd_user.sh +118 -0
  139. package/templates/workspace/tools/requirements_contract.py +285 -0
  140. package/templates/workspace/tools/requirements_contract_sync.py +290 -0
  141. package/templates/workspace/tools/requirements_flow_gen.py +250 -0
  142. package/templates/workspace/tools/server_test_runner.py +1902 -0
  143. package/templates/workspace/tools/systemd/iflow-watchdog@.service +16 -0
  144. package/templates/workspace/tools/systemd/iflow-watchdog@.timer +11 -0
  145. package/templates/workspace/tools/ws_change_check.py +323 -0
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import csv
6
+ import json
7
+ import time
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+ from typing import Any, Dict, List, Optional, Set, Tuple
11
+
12
+
13
+ FLOW_SPEC_BEGIN = "<!-- FLOW_SPEC_BEGIN -->"
14
+ FLOW_SPEC_END = "<!-- FLOW_SPEC_END -->"
15
+
16
+
17
+ SCENARIO_CSV_COLUMNS = [
18
+ "Scenario_ID",
19
+ "Title",
20
+ "Steps",
21
+ "Status",
22
+ "Evidence",
23
+ "Notes",
24
+ "Created_At",
25
+ "Updated_At",
26
+ ]
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class FlowStep:
31
+ method: str
32
+ path: str
33
+ name: str = ""
34
+
35
+
36
+ @dataclass(frozen=True)
37
+ class Flow:
38
+ flow_id: str
39
+ title: str
40
+ steps: Tuple[FlowStep, ...]
41
+ notes: str = ""
42
+
43
+
44
+ def _now_utc() -> str:
45
+ return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
46
+
47
+
48
+ def _read_text(path: Path) -> str:
49
+ return path.read_text(encoding="utf-8", errors="replace")
50
+
51
+
52
+ def extract_flow_spec_json(requirements_text: str) -> Dict[str, Any]:
53
+ if FLOW_SPEC_BEGIN not in requirements_text or FLOW_SPEC_END not in requirements_text:
54
+ raise ValueError(f"missing flow spec markers: {FLOW_SPEC_BEGIN} / {FLOW_SPEC_END}")
55
+ body = requirements_text.split(FLOW_SPEC_BEGIN, 1)[1].split(FLOW_SPEC_END, 1)[0]
56
+ start = body.find("```")
57
+ if start == -1:
58
+ raise ValueError("missing fenced code block inside flow spec markers")
59
+ fence = body[start:]
60
+ lines = fence.splitlines()
61
+ if not lines:
62
+ raise ValueError("empty fenced code block")
63
+ header = lines[0].strip().lower()
64
+ if not header.startswith("```"):
65
+ raise ValueError("invalid fenced code block header")
66
+ if "json" not in header:
67
+ raise ValueError("flow spec code block must be ```json")
68
+ payload_lines: List[str] = []
69
+ for ln in lines[1:]:
70
+ if ln.strip().startswith("```"):
71
+ break
72
+ payload_lines.append(ln)
73
+ raw = "\n".join(payload_lines).strip()
74
+ if not raw:
75
+ raise ValueError("empty json in flow spec")
76
+ data = json.loads(raw)
77
+ if not isinstance(data, dict):
78
+ raise ValueError("flow spec json must be an object")
79
+ return data
80
+
81
+
82
+ def parse_flows(data: Dict[str, Any]) -> List[Flow]:
83
+ flows_raw = data.get("flows")
84
+ if flows_raw is None:
85
+ return []
86
+ if not isinstance(flows_raw, list):
87
+ raise ValueError("flow spec 'flows' must be a list")
88
+
89
+ out: List[Flow] = []
90
+ for item in flows_raw:
91
+ if not isinstance(item, dict):
92
+ continue
93
+ flow_id = str(item.get("id") or "").strip()
94
+ if not flow_id:
95
+ continue
96
+ title = str(item.get("title") or flow_id).strip()
97
+ notes = str(item.get("notes") or "").strip()
98
+ steps_raw = item.get("steps") or []
99
+ if not isinstance(steps_raw, list) or not steps_raw:
100
+ continue
101
+ steps: List[FlowStep] = []
102
+ for s in steps_raw:
103
+ if not isinstance(s, dict):
104
+ continue
105
+ method = str(s.get("method") or "GET").strip().upper()
106
+ path = str(s.get("path") or "").strip()
107
+ name = str(s.get("name") or "").strip()
108
+ if not path:
109
+ continue
110
+ steps.append(FlowStep(method=method, path=path, name=name))
111
+ if steps:
112
+ out.append(Flow(flow_id=flow_id, title=title, steps=tuple(steps), notes=notes))
113
+ return out
114
+
115
+
116
+ def _slug(text: str) -> str:
117
+ out = []
118
+ for ch in text:
119
+ if ch.isalnum() or ch in ("_", "-"):
120
+ out.append(ch)
121
+ else:
122
+ out.append("_")
123
+ s = "".join(out).strip("_")
124
+ return s[:64] if s else "flow"
125
+
126
+
127
+ def render_mermaid(flows: List[Flow]) -> str:
128
+ lines: List[str] = []
129
+ lines.append("flowchart TD")
130
+ if not flows:
131
+ lines.append(' empty["No flows defined in REQUIREMENTS.md"]')
132
+ return "\n".join(lines) + "\n"
133
+
134
+ for flow in flows:
135
+ fid = _slug(flow.flow_id)
136
+ title = flow.title.replace('"', "'")
137
+ lines.append(f' subgraph {fid}["{flow.flow_id}: {title}"]')
138
+ prev_node: Optional[str] = None
139
+ for i, step in enumerate(flow.steps, start=1):
140
+ label = f"{step.method} {step.path}".replace('"', "'")
141
+ node = f"{fid}_{i}"
142
+ lines.append(f' {node}["{label}"]')
143
+ if prev_node:
144
+ lines.append(f" {prev_node} --> {node}")
145
+ prev_node = node
146
+ lines.append(" end")
147
+ return "\n".join(lines) + "\n"
148
+
149
+
150
+ def _read_csv_rows(path: Path) -> List[Dict[str, str]]:
151
+ if not path.exists():
152
+ return []
153
+ with path.open("r", encoding="utf-8", newline="") as f:
154
+ reader = csv.DictReader(f)
155
+ return [{k: (v or "") for k, v in row.items()} for row in reader]
156
+
157
+
158
+ def _write_csv_rows(path: Path, rows: List[Dict[str, str]]) -> None:
159
+ path.parent.mkdir(parents=True, exist_ok=True)
160
+ with path.open("w", encoding="utf-8", newline="") as f:
161
+ writer = csv.DictWriter(f, fieldnames=SCENARIO_CSV_COLUMNS)
162
+ writer.writeheader()
163
+ for row in rows:
164
+ writer.writerow({k: row.get(k, "") for k in SCENARIO_CSV_COLUMNS})
165
+
166
+
167
+ def sync_scenario_csv(*, csv_path: Path, flows: List[Flow], generated_at: str) -> None:
168
+ existing = _read_csv_rows(csv_path)
169
+ existing_by_id: Dict[str, Dict[str, str]] = {}
170
+ for r in existing:
171
+ sid = (r.get("Scenario_ID", "") or "").strip()
172
+ if sid:
173
+ existing_by_id[sid] = r
174
+
175
+ out_rows: List[Dict[str, str]] = []
176
+ used_ids: Set[str] = set()
177
+
178
+ for flow in flows:
179
+ sid = flow.flow_id.strip()
180
+ used_ids.add(sid)
181
+ prev = existing_by_id.get(sid)
182
+ steps_str = " -> ".join([f"{s.method} {s.path}".strip() for s in flow.steps])
183
+ created_at = (prev.get("Created_At", "") if prev else "").strip() or generated_at
184
+ status = (prev.get("Status", "") if prev else "").strip() or "TODO"
185
+ notes = (prev.get("Notes", "") if prev else "").strip()
186
+ evidence = (prev.get("Evidence", "") if prev else "").strip()
187
+ out_rows.append(
188
+ {
189
+ "Scenario_ID": sid,
190
+ "Title": flow.title,
191
+ "Steps": steps_str,
192
+ "Status": status,
193
+ "Evidence": evidence,
194
+ "Notes": notes,
195
+ "Created_At": created_at,
196
+ "Updated_At": generated_at,
197
+ }
198
+ )
199
+
200
+ for r in existing:
201
+ sid = (r.get("Scenario_ID", "") or "").strip()
202
+ if not sid or sid in used_ids:
203
+ continue
204
+ out_rows.append(
205
+ {
206
+ "Scenario_ID": sid,
207
+ "Title": (r.get("Title", "") or "").strip(),
208
+ "Steps": (r.get("Steps", "") or "").strip(),
209
+ "Status": (r.get("Status", "") or "").strip(),
210
+ "Evidence": (r.get("Evidence", "") or "").strip(),
211
+ "Notes": (r.get("Notes", "") or "").strip(),
212
+ "Created_At": (r.get("Created_At", "") or "").strip() or generated_at,
213
+ "Updated_At": (r.get("Updated_At", "") or "").strip(),
214
+ }
215
+ )
216
+
217
+ _write_csv_rows(csv_path, out_rows)
218
+
219
+
220
+ def main(argv: List[str]) -> int:
221
+ p = argparse.ArgumentParser(description="Generate concise API flow diagram + scenario CSV from REQUIREMENTS.md FlowSpec")
222
+ p.add_argument("--workspace", default=".", help="workspace root")
223
+ p.add_argument("--requirements", default="REQUIREMENTS.md", help="requirements markdown path (relative to workspace)")
224
+ p.add_argument("--out-mermaid", default="docs/api-flow.mmd", help="output mermaid file (relative to workspace)")
225
+ p.add_argument("--out-csv", default="issues/server-scenario-issues.csv", help="output scenario CSV (relative to workspace)")
226
+ args = p.parse_args(argv)
227
+
228
+ root = Path(args.workspace).resolve()
229
+ req_path = (root / args.requirements).resolve()
230
+ if not req_path.exists():
231
+ raise SystemExit(f"missing requirements file: {req_path}")
232
+
233
+ data = extract_flow_spec_json(_read_text(req_path))
234
+ flows = parse_flows(data)
235
+
236
+ generated_at = _now_utc()
237
+ mermaid_path = (root / args.out_mermaid).resolve()
238
+ mermaid_path.parent.mkdir(parents=True, exist_ok=True)
239
+ mermaid_path.write_text(render_mermaid(flows), encoding="utf-8", errors="replace")
240
+
241
+ csv_path = (root / args.out_csv).resolve()
242
+ sync_scenario_csv(csv_path=csv_path, flows=flows, generated_at=generated_at)
243
+
244
+ print(f"OK: wrote {mermaid_path.relative_to(root)}")
245
+ print(f"OK: wrote {csv_path.relative_to(root)}")
246
+ return 0
247
+
248
+
249
+ if __name__ == "__main__":
250
+ raise SystemExit(main(__import__("sys").argv[1:]))