@manhquy/flow-skill 0.1.0-rc.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 (76) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE +21 -0
  3. package/README.md +152 -0
  4. package/README_VN.md +134 -0
  5. package/SECURITY.md +69 -0
  6. package/bin/cli.mjs +382 -0
  7. package/package.json +52 -0
  8. package/skills/flow/SKILL.md +234 -0
  9. package/skills/flow/_templates/00-idea.md +16 -0
  10. package/skills/flow/_templates/00-inspect.md +42 -0
  11. package/skills/flow/_templates/01-research.md +59 -0
  12. package/skills/flow/_templates/02-scope.md +71 -0
  13. package/skills/flow/_templates/03-prd.md +57 -0
  14. package/skills/flow/_templates/04-adr.md +21 -0
  15. package/skills/flow/_templates/05-contract.md +59 -0
  16. package/skills/flow/_templates/card.md +26 -0
  17. package/skills/flow/_templates/constitution.md +22 -0
  18. package/skills/flow/eval/fixtures/f01a/flow/01-research.md +77 -0
  19. package/skills/flow/eval/fixtures/f01b/flow/01-research.md +75 -0
  20. package/skills/flow/eval/fixtures/f02a/flow/02-scope.md +56 -0
  21. package/skills/flow/eval/fixtures/f02b/flow/02-scope.md +65 -0
  22. package/skills/flow/eval/fixtures/fcda/.flow/.gitkeep +0 -0
  23. package/skills/flow/eval/fixtures/fcda/cards/C-001.md +46 -0
  24. package/skills/flow/eval/fixtures/fcdb/.flow/.gitkeep +0 -0
  25. package/skills/flow/eval/fixtures/fcdb/cards/C-001.md +35 -0
  26. package/skills/flow/eval/manifest.tsv +7 -0
  27. package/skills/flow/harness/README.md +117 -0
  28. package/skills/flow/harness/_db.py +228 -0
  29. package/skills/flow/harness/_domain.py +161 -0
  30. package/skills/flow/harness/_presence.py +109 -0
  31. package/skills/flow/harness/flow_harness.py +1103 -0
  32. package/skills/flow/harness/repo_map.py +93 -0
  33. package/skills/flow/harness/schema/001-init.sql +129 -0
  34. package/skills/flow/harness/schema/002-story-verify.sql +9 -0
  35. package/skills/flow/harness/schema/003-tool-registry.sql +15 -0
  36. package/skills/flow/harness/schema/004-intervention.sql +15 -0
  37. package/skills/flow/harness/schema/005-tool-extensions.sql +20 -0
  38. package/skills/flow/harness/schema/009-accessed-count.sql +11 -0
  39. package/skills/flow/harness/schema/010-usage-event.sql +42 -0
  40. package/skills/flow/harness/schema/011-usage-gate-reason.sql +8 -0
  41. package/skills/flow/harness/schema/012-usage-ephemeral.sql +10 -0
  42. package/skills/flow/law/CLAUDE.md +140 -0
  43. package/skills/flow/law/DESIGN.md +141 -0
  44. package/skills/flow/law/RETRO.md +13 -0
  45. package/skills/flow/playbooks/README.md +28 -0
  46. package/skills/flow/playbooks/cloudflare-ai-gateway-qwen.md +346 -0
  47. package/skills/flow/playbooks/docker-deploy-stale-cache.md +32 -0
  48. package/skills/flow/playbooks/rag-lite-postgres-cloudflare.md +192 -0
  49. package/skills/flow/playbooks/windows-gitbash-jsonl-telemetry.md +57 -0
  50. package/skills/flow/references/adversarial-review.md +197 -0
  51. package/skills/flow/references/agent-detection.md +88 -0
  52. package/skills/flow/references/agent-stage-mapping.md +114 -0
  53. package/skills/flow/references/antigravity-integration.md +92 -0
  54. package/skills/flow/references/auto-run.md +81 -0
  55. package/skills/flow/references/claudekit-skills.md +128 -0
  56. package/skills/flow/references/codex-integration.md +104 -0
  57. package/skills/flow/references/command-dispatch.md +54 -0
  58. package/skills/flow/references/debt-and-halts.md +41 -0
  59. package/skills/flow/references/design-review-checklist.md +42 -0
  60. package/skills/flow/references/gate-eval.md +186 -0
  61. package/skills/flow/references/gate-rules.md +171 -0
  62. package/skills/flow/references/ground-truth-gates.md +49 -0
  63. package/skills/flow/references/loop-harness-2026-principles.md +52 -0
  64. package/skills/flow/references/mode-work.md +37 -0
  65. package/skills/flow/references/project-types.md +42 -0
  66. package/skills/flow/references/stage-state-machine.md +47 -0
  67. package/skills/flow/references/ui-patterns-tcr.md +49 -0
  68. package/skills/flow/runner/flow.cmd +18 -0
  69. package/skills/flow/runner/flow.sh +3297 -0
  70. package/skills-manifest.json +70 -0
  71. package/src/constants.mjs +65 -0
  72. package/src/detect.mjs +36 -0
  73. package/src/help.mjs +42 -0
  74. package/src/installer.mjs +231 -0
  75. package/src/prompt.mjs +60 -0
  76. package/src/tty.mjs +11 -0
@@ -0,0 +1,109 @@
1
+ """Tool presence probing for the inbound tool registry (stdlib only).
2
+
3
+ Ported from repository-harness crates/harness-cli/src/infrastructure.rs
4
+ (scan_tool_status, command_available, scan_target_resolves, http_reachable).
5
+
6
+ A probe NEVER raises: an absent tool is a fact to report (status 'missing'/'unknown'),
7
+ never an error that breaks a flow step. Status is one of: 'present', 'missing', 'unknown'.
8
+ Kind-aware so each agent runtime uses what it can orchestrate; an absent capability is a
9
+ clean skip. No third-party deps — only shutil / os / socket / urllib.
10
+ """
11
+
12
+ import os
13
+ import shutil
14
+ import socket
15
+ from urllib.parse import urlparse
16
+
17
+ KINDS = ("cli", "binary", "mcp", "skill", "http")
18
+
19
+
20
+ def _path_or_pathext_exists(p):
21
+ """os.path.exists, plus Windows PATHEXT fallback so an extensionless path resolves
22
+ ('C:/Program Files/Git/cmd/git' -> git.EXE). shutil.which does NOT apply PATHEXT to a
23
+ path that already contains a separator, so we check it ourselves."""
24
+ if os.path.exists(p):
25
+ return True
26
+ if os.name == "nt":
27
+ for ext in os.environ.get("PATHEXT", ".EXE;.BAT;.CMD").split(os.pathsep):
28
+ if ext and os.path.exists(p + ext):
29
+ return True
30
+ return False
31
+
32
+
33
+ def _command_available(repo_root, command):
34
+ """True if `command` resolves as a path or on PATH.
35
+
36
+ Tries the whole string first so a path containing spaces (common on Windows) resolves,
37
+ then the first whitespace token for the 'binary --arg' form. Each candidate is checked on
38
+ PATH (shutil.which, which applies PATHEXT to bare names) and as a literal/repo-relative
39
+ path (with a PATHEXT fallback for extensionless Windows paths)."""
40
+ if not command:
41
+ return False
42
+ cmd = command.strip()
43
+ if not cmd: # whitespace-only: a probe must never raise (no .split()[0] IndexError)
44
+ return False
45
+ candidates = [cmd]
46
+ first = cmd.split()[0]
47
+ if first != cmd:
48
+ candidates.append(first)
49
+ for cand in candidates:
50
+ if shutil.which(cand):
51
+ return True
52
+ if _path_or_pathext_exists(cand):
53
+ return True
54
+ if repo_root and _path_or_pathext_exists(os.path.join(repo_root, cand)):
55
+ return True
56
+ return False
57
+
58
+
59
+ def _target_resolves(repo_root, target):
60
+ """True if a declarative scan_target path (with ~ expansion) resolves on disk."""
61
+ if not target:
62
+ return False
63
+ p = os.path.expanduser(target)
64
+ if os.path.isabs(p):
65
+ return os.path.exists(p)
66
+ if os.path.exists(p):
67
+ return True
68
+ return bool(repo_root) and os.path.exists(os.path.join(repo_root, p))
69
+
70
+
71
+ def _http_reachable(target):
72
+ """True if a TCP connection to the target's host:port succeeds within 2s. Never raises.
73
+
74
+ Only http/https targets are probed (mirrors repository-harness): a non-http scheme or a
75
+ bare word is not a reachable-by-TCP endpoint, and probing it would trigger slow DNS/connect
76
+ on an unrelated host. Such targets fall through to the path-resolve fallback in scan_tool_status."""
77
+ if not (target.startswith("http://") or target.startswith("https://")):
78
+ return False
79
+ try:
80
+ u = urlparse(target, scheme="http")
81
+ host = u.hostname
82
+ if not host:
83
+ return False
84
+ port = u.port or (443 if u.scheme == "https" else 80)
85
+ with socket.create_connection((host, port), timeout=2):
86
+ return True
87
+ except Exception:
88
+ return False
89
+
90
+
91
+ def scan_tool_status(repo_root, kind, command, scan_target):
92
+ """Kind-aware presence probe. Returns (status, detail); status in present/missing/unknown."""
93
+ kind = (kind or "cli").lower()
94
+ if kind in ("cli", "binary"):
95
+ return ("present", command or "") if _command_available(repo_root, command) \
96
+ else ("missing", command or "")
97
+ if kind in ("mcp", "skill"):
98
+ t = (scan_target or "").strip()
99
+ if not t:
100
+ return "unknown", "no scan target; agent confirms availability"
101
+ return ("present", t) if _target_resolves(repo_root, t) else ("missing", t)
102
+ if kind == "http":
103
+ t = (scan_target or "").strip()
104
+ if not t:
105
+ return "unknown", "no scan target"
106
+ if _http_reachable(t) or _target_resolves(repo_root, t):
107
+ return "present", t
108
+ return "missing", t
109
+ return "unknown", ""