easy-coding-harness 0.5.2-beta.0 → 0.6.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.
@@ -4,103 +4,9 @@ import os
4
4
  from pathlib import Path
5
5
  import sys
6
6
 
7
- from easy_coding_state import StateError, load_session, snapshot_state, transition_task
7
+ from easy_coding_state import load_session
8
8
  from easy_coding_status import build_status_context
9
9
 
10
- PROMPT_KEYS = ("prompt", "user_prompt", "userPrompt", "message", "text", "input")
11
-
12
- NEGATIVE_OR_REVISION_PATTERNS = (
13
- "修改",
14
- "调整",
15
- "重写",
16
- "重新",
17
- "补充",
18
- "换个",
19
- "换一",
20
- "不要",
21
- "别",
22
- "取消",
23
- "暂停",
24
- "等一下",
25
- "先别",
26
- "有问题",
27
- "还有问题",
28
- "不对",
29
- "不是",
30
- "不行",
31
- "继续修复",
32
- "需要修复",
33
- "再修复",
34
- "修一下",
35
- "修正",
36
- "?",
37
- "?",
38
- "revise",
39
- "change",
40
- "cancel",
41
- "pause",
42
- "wait",
43
- "stop",
44
- "don't",
45
- "do not",
46
- "hold",
47
- "problem",
48
- "issue",
49
- "keep fixing",
50
- "continue fixing",
51
- "needs fixing",
52
- )
53
-
54
- WAITING_CONFIRM_PATTERNS = (
55
- "确认",
56
- "开始",
57
- "执行",
58
- "实施",
59
- "按方案",
60
- "按计划",
61
- "没问题",
62
- "可以",
63
- "同意",
64
- "继续",
65
- "go ahead",
66
- "proceed",
67
- "start",
68
- "implement",
69
- "approve",
70
- "approved",
71
- "yes",
72
- "ok",
73
- "okay",
74
- "confirm",
75
- "looks good",
76
- "ship it",
77
- )
78
-
79
- VERIFICATION_ACCEPT_PATTERNS = (
80
- "验收通过",
81
- "接受",
82
- "通过",
83
- "可以结束",
84
- "归档",
85
- "完成",
86
- "确认完成",
87
- "没问题",
88
- "可以",
89
- "同意",
90
- "accept",
91
- "accepted",
92
- "approve",
93
- "approved",
94
- "looks good",
95
- "complete",
96
- "finish",
97
- "archive",
98
- "done",
99
- "ship it",
100
- )
101
-
102
- WAITING_CONFIRM_EXACT = {"1", "1.", "开始实施", "确认执行"}
103
-
104
10
 
105
11
  def configure_stdio() -> None:
106
12
  for stream in (sys.stdin, sys.stdout, sys.stderr):
@@ -115,56 +21,6 @@ def read_payload() -> dict:
115
21
  return {}
116
22
 
117
23
 
118
- def coerce_prompt_text(value: object) -> str:
119
- if isinstance(value, str):
120
- return value
121
- if isinstance(value, list):
122
- return "\n".join(part for item in value if (part := coerce_prompt_text(item)))
123
- if isinstance(value, dict):
124
- parts: list[str] = []
125
- for key in PROMPT_KEYS:
126
- if key in value:
127
- text = coerce_prompt_text(value[key])
128
- if text:
129
- parts.append(text)
130
- if "content" in value:
131
- text = coerce_prompt_text(value["content"])
132
- if text:
133
- parts.append(text)
134
- return "\n".join(parts)
135
- return ""
136
-
137
-
138
- def extract_user_prompt(payload: dict) -> str:
139
- for key in PROMPT_KEYS:
140
- if key not in payload:
141
- continue
142
- text = coerce_prompt_text(payload[key])
143
- if text:
144
- return text
145
- return ""
146
-
147
-
148
- def normalize_prompt(text: str) -> str:
149
- return " ".join(text.casefold().strip().split())
150
-
151
-
152
- def has_any(text: str, patterns: tuple[str, ...]) -> bool:
153
- return any(pattern in text for pattern in patterns)
154
-
155
-
156
- def infer_confirmed_transition(current_stage: str, prompt: str) -> str | None:
157
- normalized = normalize_prompt(prompt)
158
- if not normalized or has_any(normalized, NEGATIVE_OR_REVISION_PATTERNS):
159
- return None
160
- if current_stage == "WAITING_CONFIRM":
161
- if normalized in WAITING_CONFIRM_EXACT or has_any(normalized, WAITING_CONFIRM_PATTERNS):
162
- return "IMPLEMENT"
163
- if current_stage == "VERIFICATION" and has_any(normalized, VERIFICATION_ACCEPT_PATTERNS):
164
- return "MEMORY_SHORT"
165
- return None
166
-
167
-
168
24
  def find_ec_root(start: Path) -> Path | None:
169
25
  current = start.resolve()
170
26
  while True:
@@ -190,35 +46,6 @@ def detect_agent() -> str:
190
46
  return "unknown"
191
47
 
192
48
 
193
- def preflight_confirmed_transition(root: Path, session: dict, payload: dict, agent: str) -> dict:
194
- prompt = extract_user_prompt(payload)
195
- if not prompt:
196
- return session
197
-
198
- state = snapshot_state(root, session=session)
199
- task_id = state.get("current_task")
200
- if not task_id or state.get("task_missing") or state.get("is_terminal"):
201
- return session
202
-
203
- target_stage = infer_confirmed_transition(str(state.get("status") or ""), prompt)
204
- if not target_stage:
205
- return session
206
-
207
- try:
208
- transition_task(
209
- root,
210
- target_stage,
211
- agent,
212
- task_id=str(task_id),
213
- session_file=str(state["session_file"]),
214
- )
215
- except StateError:
216
- return load_session(root) or session
217
-
218
- # Read after write so the status line renders the authoritative latest stage.
219
- return load_session(root) or session
220
-
221
-
222
49
  def emit(event_name: str, context: str) -> None:
223
50
  print(
224
51
  json.dumps(
@@ -249,8 +76,6 @@ def main() -> int:
249
76
 
250
77
  event_name = payload.get("hook_event_name") or payload.get("hookEventName") or "UserPromptSubmit"
251
78
  agent = detect_agent()
252
- if event_name == "UserPromptSubmit":
253
- session = preflight_confirmed_transition(root, session, payload, agent)
254
79
  emit(event_name, build_status_context(root, session, agent))
255
80
  return 0
256
81
 
@@ -5,7 +5,7 @@ from datetime import datetime, timezone
5
5
  from pathlib import Path
6
6
  import sys
7
7
 
8
- from easy_coding_state import load_session, write_session
8
+ from easy_coding_state import load_session, normalize_legacy_task, write_session
9
9
  from easy_coding_status import build_status_context
10
10
 
11
11
 
@@ -118,6 +118,7 @@ def migrate_legacy_state(root: Path, agent: str) -> dict | None:
118
118
  task["test_strategy_confirmed"] = True
119
119
  if old_state.get("repo_paths"):
120
120
  task["repo_paths"] = old_state["repo_paths"]
121
+ normalize_legacy_task(task)
121
122
  write_json(task_path, task)
122
123
 
123
124
  # Remove legacy state.json