@techierathore/techieflow 1.0.4 → 1.1.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 (148) hide show
  1. package/.claude/commands/TechieFlow/agents/flow-master.md +2 -0
  2. package/.claude/commands/TechieFlow/agents/verifier.md +2 -2
  3. package/.claude/commands/TechieFlow/tasks/_develop-mode.md +34 -0
  4. package/.claude/commands/TechieFlow/tasks/_owner-language.md +1 -0
  5. package/.claude/commands/TechieFlow/tasks/_status-update-gate.md +4 -3
  6. package/.claude/commands/TechieFlow/tasks/_yolo-mode.md +2 -2
  7. package/.claude/commands/TechieFlow/tasks/amend-docs.md +2 -2
  8. package/.claude/commands/TechieFlow/tasks/day1-brownfield.md +3 -3
  9. package/.claude/commands/TechieFlow/tasks/day1-greenfield.md +5 -5
  10. package/.claude/commands/TechieFlow/tasks/develop-end-to-end.md +30 -0
  11. package/.claude/commands/TechieFlow/tasks/fix-issues.md +3 -2
  12. package/.claude/commands/TechieFlow/tasks/generate-html.md +2 -2
  13. package/.claude/commands/TechieFlow/tasks/handoff-phase.md +2 -2
  14. package/.claude/commands/TechieFlow/tasks/mockups.md +2 -2
  15. package/.claude/commands/TechieFlow/tasks/productguide.md +2 -2
  16. package/.claude/commands/TechieFlow/tasks/render-workflow-docs.md +1 -1
  17. package/.claude/commands/TechieFlow/tasks/triage-and-fix.md +2 -2
  18. package/.claude/commands/TechieFlow/tasks/triage-issues.md +2 -2
  19. package/.claude/commands/TechieFlow/tasks/verify-phase.md +12 -11
  20. package/.opencode/plugin/techieflow.js +194 -14
  21. package/.tfcore/agents/flow-master.md +2 -0
  22. package/.tfcore/agents/verifier.md +2 -2
  23. package/.tfcore/core-config.yaml +2 -1
  24. package/.tfcore/hooks/block-git.sh +4 -2
  25. package/.tfcore/hooks/guard-build.sh +5 -1
  26. package/.tfcore/hooks/guard-db.sh +112 -13
  27. package/.tfcore/hooks/guard-status-html.sh +86 -2
  28. package/.tfcore/hooks/guard-verify-deps.sh +16 -1
  29. package/.tfcore/hooks/guard-verify.sh +8 -3
  30. package/.tfcore/hooks/sweep-artifacts.sh +46 -0
  31. package/.tfcore/hooks/yolo-allow.sh +27 -0
  32. package/.tfcore/standards/blazor-zoom.cs.txt +191 -0
  33. package/.tfcore/standards/coding-standards-dotnet.md +31 -3
  34. package/.tfcore/standards/owner-words.txt +23 -0
  35. package/.tfcore/tasks/_develop-mode.md +34 -0
  36. package/.tfcore/tasks/_owner-language.md +1 -0
  37. package/.tfcore/tasks/_status-update-gate.md +4 -3
  38. package/.tfcore/tasks/_yolo-mode.md +2 -2
  39. package/.tfcore/tasks/amend-docs.md +2 -2
  40. package/.tfcore/tasks/day1-brownfield.md +3 -3
  41. package/.tfcore/tasks/day1-greenfield.md +5 -5
  42. package/.tfcore/tasks/develop-end-to-end.md +30 -0
  43. package/.tfcore/tasks/fix-issues.md +3 -2
  44. package/.tfcore/tasks/generate-html.md +2 -2
  45. package/.tfcore/tasks/handoff-phase.md +2 -2
  46. package/.tfcore/tasks/mockups.md +2 -2
  47. package/.tfcore/tasks/productguide.md +2 -2
  48. package/.tfcore/tasks/render-workflow-docs.md +1 -1
  49. package/.tfcore/tasks/triage-and-fix.md +2 -2
  50. package/.tfcore/tasks/triage-issues.md +2 -2
  51. package/.tfcore/tasks/verify-phase.md +12 -11
  52. package/.tfcore/telemetry/SCHEMA.md +10 -2
  53. package/.tfcore/telemetry/install-metrics.sh +3 -2
  54. package/.tfcore/telemetry/tf-metrics.sh +38 -2
  55. package/.tfcore/templates/stack-defaults/dotnet.md +3 -1
  56. package/.tfcore/templates/v4custom/app-agents-md-tmpl.md +6 -0
  57. package/.tfcore/templates/v4custom/app-architecture-tmpl.md +5 -0
  58. package/.tfcore/templates/v4custom/app-brd-tmpl.md +7 -4
  59. package/.tfcore/templates/v4custom/app-checklist-tmpl.md +11 -0
  60. package/.tfcore/templates/v4custom/app-phase-brd-tmpl.md +94 -0
  61. package/.tfcore/templates/v4custom/app-phase-uidesign-tmpl.md +60 -0
  62. package/.tfcore/templates/v4custom/app-phases-tmpl.md +2 -1
  63. package/.tfcore/templates/v4custom/app-uidesign-tmpl.md +4 -2
  64. package/.tfcore/templates/v4custom/build-subagent-prompt.md +2 -2
  65. package/.tfcore/templates/v4custom/html-render-shell.md +6 -2
  66. package/.tfcore/utils/__pycache__/tf-devguide-list.cpython-312.pyc +0 -0
  67. package/.tfcore/utils/__pycache__/tf-doc-check.cpython-312.pyc +0 -0
  68. package/.tfcore/utils/__pycache__/tf-split-brd.cpython-312.pyc +0 -0
  69. package/.tfcore/utils/__pycache__/tf-status-facts.cpython-312.pyc +0 -0
  70. package/.tfcore/utils/__pycache__/tf-verify-list.cpython-312.pyc +0 -0
  71. package/.tfcore/utils/tf-appium.mjs +179 -0
  72. package/.tfcore/utils/tf-assets-browser.mjs +96 -0
  73. package/.tfcore/utils/tf-assets.sh +97 -12
  74. package/.tfcore/utils/tf-brd-status.py +14 -5
  75. package/.tfcore/utils/tf-build-list.py +95 -12
  76. package/.tfcore/utils/tf-build-list.sh +2 -1
  77. package/.tfcore/utils/tf-build.sh +163 -15
  78. package/.tfcore/utils/tf-checklist-edit.py +21 -3
  79. package/.tfcore/utils/tf-ci-repro.py +685 -0
  80. package/.tfcore/utils/tf-ci-repro.sh +24 -0
  81. package/.tfcore/utils/tf-day1-files.py +55 -28
  82. package/.tfcore/utils/tf-develop.sh +264 -0
  83. package/.tfcore/utils/tf-devguide-list.py +53 -24
  84. package/.tfcore/utils/tf-doc-check.py +218 -26
  85. package/.tfcore/utils/tf-doc-tests.sh +116 -0
  86. package/.tfcore/utils/tf-emit.sh +132 -45
  87. package/.tfcore/utils/tf-feedback.sh +13 -0
  88. package/.tfcore/utils/tf-fix-close.sh +87 -31
  89. package/.tfcore/utils/tf-goal.sh +12 -12
  90. package/.tfcore/utils/tf-harness.sh +9 -4
  91. package/.tfcore/utils/tf-lock.sh +29 -0
  92. package/.tfcore/utils/tf-log-miss.py +34 -8
  93. package/.tfcore/utils/tf-login.mjs +167 -0
  94. package/.tfcore/utils/tf-maccatalyst-check.sh +92 -0
  95. package/.tfcore/utils/tf-menus.mjs +401 -0
  96. package/.tfcore/utils/tf-misses-md.py +10 -4
  97. package/.tfcore/utils/tf-mockup-parity.mjs +763 -71
  98. package/.tfcore/utils/tf-mockup-parity.sh +25 -2
  99. package/.tfcore/utils/tf-owner-text.py +233 -0
  100. package/.tfcore/utils/tf-owner-text.sh +14 -0
  101. package/.tfcore/utils/tf-phase.sh +38 -4
  102. package/.tfcore/utils/tf-portable.sh +230 -0
  103. package/.tfcore/utils/tf-render-html.py +79 -5
  104. package/.tfcore/utils/tf-req-ids.py +36 -0
  105. package/.tfcore/utils/tf-selfcheck.sh +39 -6
  106. package/.tfcore/utils/tf-split-brd.py +11 -1
  107. package/.tfcore/utils/tf-stack-check.sh +3 -0
  108. package/.tfcore/utils/tf-status-evidence.sh +11 -9
  109. package/.tfcore/utils/tf-status-facts.py +160 -45
  110. package/.tfcore/utils/tf-theme.mjs +189 -0
  111. package/.tfcore/utils/tf-triage.py +74 -17
  112. package/.tfcore/utils/tf-triage.sh +2 -0
  113. package/.tfcore/utils/tf-verify-boot.sh +529 -54
  114. package/.tfcore/utils/tf-verify-emit.sh +57 -17
  115. package/.tfcore/utils/tf-verify-env.sh +33 -4
  116. package/.tfcore/utils/tf-verify-list.py +290 -24
  117. package/.tfcore/utils/tf-verify-list.sh +3 -1
  118. package/.tfcore/utils/tf-verify-native.mjs +307 -0
  119. package/.tfcore/utils/tf-verify-screens.mjs +341 -44
  120. package/.tfcore/utils/tf-verify-screens.sh +23 -5
  121. package/.tfcore/utils/tf-verify-tests.sh +310 -19
  122. package/.tfcore/utils/tf-verify-verdict.py +163 -21
  123. package/.tfcore/utils/tf-verify-zoom.mjs +193 -0
  124. package/.tfcore/utils/tf-verify-zoom.sh +29 -0
  125. package/.tfcore/utils/tf-yolo-alias.sh +84 -0
  126. package/.tfcore/utils/tf-yolo-perms.py +135 -0
  127. package/.tfcore/utils/tf-yolo-start.sh +44 -0
  128. package/.tfcore/utils/tf-yolo.sh +31 -3
  129. package/.tfcore/utils/tf_defect.py +27 -0
  130. package/.tfcore/utils/tf_feedback.py +272 -0
  131. package/.tfcore/utils/tf_roadmap.py +35 -0
  132. package/.tfcore/utils/tf_stack_check.py +93 -0
  133. package/README.md +6 -2
  134. package/docs/TechieFlow-Installation.md +5 -3
  135. package/opencode.jsonc +6 -2
  136. package/package.json +1 -1
  137. package/scripts/install.mjs +13 -2
  138. package/.tfcore/utils/__pycache__/tf-brd-status.cpython-312.pyc +0 -0
  139. package/.tfcore/utils/__pycache__/tf-codex-bind.cpython-312.pyc +0 -0
  140. package/.tfcore/utils/__pycache__/tf-codex-telemetry.cpython-312.pyc +0 -0
  141. package/.tfcore/utils/__pycache__/tf-day1-files.cpython-312.pyc +0 -0
  142. package/.tfcore/utils/__pycache__/tf-log-miss.cpython-312.pyc +0 -0
  143. package/.tfcore/utils/__pycache__/tf-misses-md.cpython-312.pyc +0 -0
  144. package/.tfcore/utils/__pycache__/tf-mockups-locate.cpython-312.pyc +0 -0
  145. package/.tfcore/utils/__pycache__/tf-opencode-audit.cpython-312.pyc +0 -0
  146. package/.tfcore/utils/__pycache__/tf-render-html.cpython-312.pyc +0 -0
  147. package/.tfcore/utils/__pycache__/tf-triage.cpython-312.pyc +0 -0
  148. package/.tfcore/utils/__pycache__/tf-verify-verdict.cpython-312.pyc +0 -0
@@ -8,6 +8,9 @@
8
8
  bash .tfcore/utils/tf-triage.sh <App> note <REQ> "<could not reproduce: what was tried>"
9
9
  bash .tfcore/utils/tf-triage.sh <App> close [--started <ISO>] [--verify-ran] [--cmd triage-issues|fix-issues]
10
10
 
11
+ demote, new and note take --phase N for another phase's checklist; without it demote and note find the
12
+ row in whichever docs/<App>-Checklist.md or docs/<App>-P<N>-Checklist.md holds it.
13
+
11
14
  demote the row goes to Needs re-verify (% capped at 75) with a dated Remark holding the symptom in the
12
15
  reporter's words, the evidence path and the kind.
13
16
  new a defect no row covers: the next free id in the prefix, a Not Started row, a detail entry with the
@@ -20,7 +23,8 @@ close what triage owes the telemetry, from the actions above (tests/.artifacts
20
23
  spec for a new row, which the spec never had) (duplicates collapsed through
21
24
  tf-emit.sh --open-miss; the origin run looked up with --origin-of), then the run record. It also
22
25
  lists every file under src/, source/ or tests/ changed since the start: a triage that edited code
23
- is reported and logged as an instruction-ignored miss (FR-28).
26
+ is reported and logged as an instruction-ignored miss (FR-28). Only actions logged since the start
27
+ count, and a close empties the list (TrBlazeUI TF-001).
24
28
  Exit 0 · 2 could not run.
25
29
  """
26
30
  import datetime
@@ -58,12 +62,47 @@ def cfg_phase():
58
62
  return 1
59
63
 
60
64
 
61
- def checklist(app):
62
- ph = cfg_phase()
63
- p = os.path.join("docs", f"{app}-Checklist.md" if ph <= 1 else f"{app}-P{ph}-Checklist.md")
64
- if not os.path.isfile(p):
65
- die(f"{p} does not exist")
66
- return p
65
+ def cfg_project_type():
66
+ """metrics.project_type from core-config.yaml: a library or docs project has no mockups."""
67
+ p = os.path.join(".tfcore", "core-config.yaml")
68
+ if os.path.isfile(p):
69
+ import re
70
+ m = re.search(r"(?m)^\s+project_type:\s*(\S+)", open(p, encoding="utf-8").read())
71
+ if m:
72
+ return m.group(1).strip("'\"").lower()
73
+ return "app"
74
+
75
+
76
+ def phase_checklist(app, ph):
77
+ return os.path.join("docs", f"{app}-Checklist.md" if ph <= 1 else f"{app}-P{ph}-Checklist.md")
78
+
79
+
80
+ def checklist(app, argv, ce, rid=None):
81
+ """--phase N names the checklist, as tf-verify-list.py takes it. Without it: the appPhase
82
+ checklist, or, for a row that is not there, the one earlier-phase checklist that holds it —
83
+ a Phase 3 verify finds Phase 1 rows failing, and demote could not reach them (TF-051)."""
84
+ if "--phase" in argv:
85
+ v = opt(argv, "--phase", "")
86
+ if not v.isdigit():
87
+ die("--phase needs a number")
88
+ p = phase_checklist(app, int(v))
89
+ if not os.path.isfile(p):
90
+ die(f"{p} does not exist")
91
+ return p
92
+ p = phase_checklist(app, cfg_phase())
93
+ if rid is None or (os.path.isfile(p) and rid in ce.rows(ce.read(p))):
94
+ if not os.path.isfile(p):
95
+ die(f"{p} does not exist")
96
+ return p
97
+ import glob
98
+ every = sorted(set(glob.glob(os.path.join("docs", f"{app}-Checklist.md")) + glob.glob(os.path.join("docs", f"{app}-P*-Checklist.md"))))
99
+ hits = [c for c in every if rid in ce.rows(ce.read(c))]
100
+ if len(hits) == 1:
101
+ print(f"note: {rid} is a row of {hits[0]}, not of {p}; written there")
102
+ return hits[0]
103
+ if len(hits) > 1:
104
+ die(f"{rid} is a row of {', '.join(hits)}; name one with --phase N")
105
+ die(f"{rid} is not a row of {', '.join(every) or p}")
67
106
 
68
107
 
69
108
  def log_load():
@@ -112,7 +151,6 @@ def main(argv):
112
151
  return 0 if len(argv) > 1 else 2
113
152
  app, verb = argv[1], argv[2]
114
153
  ce = mod()
115
- cl = checklist(app)
116
154
  log = log_load()
117
155
  log.setdefault("app", app)
118
156
  now = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
@@ -121,6 +159,7 @@ def main(argv):
121
159
  if len(argv) < 5:
122
160
  die("demote needs <REQ> \"<symptom>\"")
123
161
  rid, symptom = argv[3].upper(), argv[4]
162
+ cl = checklist(app, argv, ce, rid)
124
163
  kind = opt(argv, "--kind"); ev = opt(argv, "--evidence"); src = opt(argv, "--source", "owner")
125
164
  prior = ce.demote(cl, rid, symptom, kind=kind, evidence=ev, source=src, prefix="⚠ prod bug" if src == "production" else "⚠ UAT bug")
126
165
  if prior is None:
@@ -136,9 +175,10 @@ def main(argv):
136
175
  if len(argv) < 5:
137
176
  die("new needs \"<title>\" \"<acceptance>\"")
138
177
  title, acc = argv[3], argv[4]
178
+ cl = checklist(app, argv, ce)
139
179
  prefix = opt(argv, "--prefix", "FN").upper(); section = opt(argv, "--section"); ev = opt(argv, "--evidence")
140
180
  src = opt(argv, "--source", "owner"); mockup = opt(argv, "--mockup")
141
- if prefix == "UI" and not mockup:
181
+ if prefix == "UI" and not mockup and cfg_project_type() not in ("library", "docs"): # TrBlazeUI TF-003
142
182
  print("note: a UI row needs a mockup link; pass --mockup docs/mockups/<screen>.html or the checker will flag it")
143
183
  rid = ce.add_row(cl, prefix, title, acc, section=section, mockup=mockup,
144
184
  remark=f"logged from {'production' if src == 'production' else 'UAT'} {ce.TODAY}" + (f" (evidence: {ev})" if ev else ""))
@@ -152,6 +192,7 @@ def main(argv):
152
192
  if len(argv) < 5:
153
193
  die("note needs <REQ> \"<text>\"")
154
194
  rid = argv[3].upper()
195
+ cl = checklist(app, argv, ce, rid)
155
196
  if ce.note(cl, rid, argv[4]) is None:
156
197
  die(f"{rid} is not a row of {cl}")
157
198
  log["actions"].append({"verb": "note", "req_id": rid, "symptom": argv[4], "ts": now})
@@ -162,9 +203,11 @@ def main(argv):
162
203
  if verb == "close":
163
204
  started = opt(argv, "--started") or subprocess.run(["bash", os.path.join(HERE, "tf-phase.sh"), "show"], capture_output=True, text=True).stdout
164
205
  if started.startswith("{"):
165
- import re
166
- m = re.search(r'"started":"([^"]*)"', started)
167
- started = m.group(1) if m else ""
206
+ # the marker's own started, never its "outer" block's (TF-052 follow-up)
207
+ try:
208
+ started = (json.loads(started) or {}).get("started") or ""
209
+ except ValueError:
210
+ started = ""
168
211
  started = started.strip() if started and not started.startswith("none") else ""
169
212
  cmd = opt(argv, "--cmd", "triage-issues")
170
213
  # code untouched?
@@ -173,16 +216,25 @@ def main(argv):
173
216
  t0 = datetime.datetime.strptime(started, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc).timestamp()
174
217
  for top in ("src", "source", "tests"):
175
218
  for d, dirs, files in os.walk(top):
176
- dirs[:] = [x for x in dirs if x not in ("bin", "obj", "node_modules", ".artifacts", "TestResults")]
219
+ # a running app's own log files are not code (AppManager TF-026)
220
+ dirs[:] = [x for x in dirs if x not in ("bin", "obj", "node_modules", ".artifacts", "TestResults")
221
+ and x.lower() not in ("logs", "log")]
177
222
  for f in files:
223
+ if f.lower().endswith(".log"):
224
+ continue
178
225
  p = os.path.join(d, f)
179
226
  try:
180
227
  if os.path.getmtime(p) > t0:
181
228
  changed.append(p.replace("\\", "/"))
182
229
  except OSError:
183
230
  pass
184
- acts = [a for a in log.get("actions", []) if a["verb"] in ("demote", "new")]
231
+ # only this triage's actions: an earlier run's leftovers were logged again under today's run (TrBlazeUI TF-001)
232
+ stale = [a for a in log.get("actions", []) if started and (a.get("ts") or "") < started]
233
+ if stale:
234
+ print(f" skipped {len(stale)} action(s) from before {started} — an earlier triage's, already closed or abandoned")
235
+ acts = [a for a in log.get("actions", []) if a["verb"] in ("demote", "new") and a not in stale]
185
236
  gates = misses = 0
237
+ failed = []
186
238
  for a in acts:
187
239
  rid = a["req_id"]; cls_req = rid.split("-")[1]
188
240
  att = q("--next-attempt", rid) or "1"
@@ -192,7 +244,9 @@ def main(argv):
192
244
  "gate": "escaped", "gates_run": [], "failure_class": fc, "prior_verdict": a.get("prior")}
193
245
  if emit("gates", rec):
194
246
  gates += 1
195
- mc = ("unspecified-gap" if a["verb"] == "new" else "regression" if (a.get("prior") or "").lower().startswith("verified") else "wrong-behaviour")
247
+ else:
248
+ failed.append(a)
249
+ mc =("unspecified-gap" if a["verb"] == "new" else "regression" if (a.get("prior") or "").lower().startswith("verified") else "wrong-behaviour")
196
250
  opened = q("--open-miss", rid)
197
251
  if opened and opened.split()[-1] == mc:
198
252
  print(f" {rid}: already open as {opened.split()[0]} ({mc}); no second miss")
@@ -210,9 +264,11 @@ def main(argv):
210
264
  if emit("misses", m):
211
265
  misses += 1
212
266
  a["miss_id"] = mid
213
- if changed and cmd == "triage-issues" and not log.get("code_miss_id"):
267
+ elif a not in failed:
268
+ failed.append(a)
269
+ if changed and cmd == "triage-issues" and log.get("code_miss_run") != started:
214
270
  mid = q("--next-miss-id")
215
- log["code_miss_id"] = mid
271
+ log["code_miss_id"] = mid; log["code_miss_run"] = started
216
272
  emit("misses", {"kind": "miss", "miss_id": mid, "req_id": None, "req_class": None, "miss_class": "other", "artifact": "src",
217
273
  "severity": "major", "why_missed": "instruction-ignored", "origin_phase": "triage-issues", "origin_agent": "flow-master",
218
274
  "found_by": "gate", "found_phase": "triage-issues", "found_gate": None, "found_run_id": started, "failure_class": "other",
@@ -232,6 +288,7 @@ def main(argv):
232
288
  else:
233
289
  ok = None
234
290
  log["closed"] = now
291
+ log["actions"] = failed # a closed action is never closed again; one whose record was refused waits for the next close
235
292
  log_save(log)
236
293
  print(f"triage: {len(acts)} row(s) logged — {gates} gate record(s) (escaped), {misses} miss(es)"
237
294
  + (f", run record {'written' if ok else 'not written'}" if ok is not None else "") + f"; code untouched: {'yes' if not changed else 'NO'}")
@@ -6,6 +6,8 @@
6
6
  # bash .tfcore/utils/tf-triage.sh <App> note <REQ> "<could not reproduce: what was tried>"
7
7
  # bash .tfcore/utils/tf-triage.sh <App> close [--started <ISO>] [--cmd triage-issues|fix-issues]
8
8
  #
9
+ # demote, new and note take --phase N; without it a row of an earlier phase's checklist is found (TF-051).
10
+ #
9
11
  # demote: Needs re-verify with a dated Remark in the reporter's words. new: a Not Started row with its
10
12
  # acceptance line and BRD-pending. note: a remark, no status change. close: the escaped gate records,
11
13
  # one miss per row (found by the owner, the symptom as `what`, duplicates collapsed), the run record,