easy-coding-harness 0.8.1-beta.0 → 0.8.1-beta.2
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.
- package/CHANGELOG.md +14 -0
- package/dist/cli.js +104 -42
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/claude/settings.json +0 -10
- package/templates/codex/hooks.json +4 -2
- package/templates/common/bundled-skills/ec-init/SKILL.md +23 -3
- package/templates/common/bundled-skills/ec-meta/references/local-architecture/README.md +2 -1
- package/templates/common/bundled-skills/ec-meta/references/platform-files/README.md +19 -15
- package/templates/common/skills/ec-git/SKILL.md +15 -6
- package/templates/common/skills/ec-memory/SKILL.md +8 -3
- package/templates/qoder/settings.json +1 -10
- package/templates/runtime/memory/SHORT_MEMORY_TEMPLATE.md +7 -4
- package/templates/runtime/templates/dev-spec-skeleton.md +1 -1
- package/templates/shared-hooks/easy_coding_state.py +328 -11
- package/templates/shared-hooks/inject-subagent-context.py +19 -3
- package/templates/shared-hooks/inject-workflow-state.py +3 -6
- package/templates/shared-hooks/session-start.py +3 -108
package/package.json
CHANGED
|
@@ -44,10 +44,30 @@ Field whitelist: `mode`, `language`, `test.*`, `build.*`, `lint.*`. Do not inven
|
|
|
44
44
|
top-level keys. Do not copy any CLI-owned field (`harness_version`, `agents`, …) into this
|
|
45
45
|
file.
|
|
46
46
|
|
|
47
|
-
##
|
|
47
|
+
## Project-init preflight (run first — read-only)
|
|
48
48
|
|
|
49
49
|
1. Read `.easy-coding/tasks/project-init/task.json`.
|
|
50
50
|
- File missing → the CLI never ran. Tell the user to run `easy-coding init` first. Stop.
|
|
51
|
+
- File present → record its `status` for the entry dispatch below, but do not start the
|
|
52
|
+
compliance scan or initialization yet.
|
|
53
|
+
2. Do not call the state API or write any project asset until this file-existence check passes.
|
|
54
|
+
|
|
55
|
+
## Session path resolution (run after preflight — before any project write)
|
|
56
|
+
|
|
57
|
+
Resolve one stable session path `<P>` and reuse it for the entire skill run:
|
|
58
|
+
|
|
59
|
+
1. If hook context contains `[easy-coding:session-file:P]`, use that exact path.
|
|
60
|
+
2. Otherwise run
|
|
61
|
+
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py snapshot --agent <agent-id>`
|
|
62
|
+
and use the returned `session_file` as `<P>`. This is the compatibility path for an explicit
|
|
63
|
+
ec-init invocation before the platform has surfaced hook context.
|
|
64
|
+
3. If snapshot fails or does not return a safe session path, stop before writing any project
|
|
65
|
+
asset and tell the user to enable or approve the platform hooks. Never execute a command with
|
|
66
|
+
the literal placeholder `<P>`.
|
|
67
|
+
|
|
68
|
+
## Entry dispatch (idempotency — run after session resolution)
|
|
69
|
+
|
|
70
|
+
1. Use the `status` read during the project-init preflight.
|
|
51
71
|
- `status == "COMPLETE"` → already initialized. Run the **compliance scan** (see below),
|
|
52
72
|
then exit.
|
|
53
73
|
- `status == "PENDING"` → proceed with full initialization.
|
|
@@ -89,7 +109,7 @@ On decline: exit with the gap list as a reference for the user to address manual
|
|
|
89
109
|
|
|
90
110
|
**Clear upgrade marker:** After the compliance scan completes (whether all checks passed or
|
|
91
111
|
gaps were fixed), run
|
|
92
|
-
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py project-init-complete --agent <agent-id>`.
|
|
112
|
+
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py project-init-complete --session-file <P> --agent <agent-id>`.
|
|
93
113
|
This removes `pending_init_since` and clears the "Waiting init · Upgrade" status line so the
|
|
94
114
|
user is no longer prompted on every session. Use the returned `status_context` as the current
|
|
95
115
|
status source.
|
|
@@ -147,7 +167,7 @@ agent must be able to see what was generated and on what evidence.
|
|
|
147
167
|
Also ensure `SHORT_MEMORY_TEMPLATE.md` exists in `memory/` as format reference. Never write
|
|
148
168
|
fake entries.
|
|
149
169
|
7. **Mark complete** — write the final `init_log` entry, then run
|
|
150
|
-
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py project-init-complete --agent <agent-id>`.
|
|
170
|
+
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py project-init-complete --session-file <P> --agent <agent-id>`.
|
|
151
171
|
Use the returned `status_context`, then tell the user initialization is done and daily work
|
|
152
172
|
goes through `{{skill_trigger}}ec-workflow`.
|
|
153
173
|
|
|
@@ -52,7 +52,8 @@ confirms two critical gates, lite uses the same gates but forces IMPLEMENT -> VE
|
|
|
52
52
|
and auto advances legal edges automatically. Lite never enters REVIEW. VERIFICATION remains
|
|
53
53
|
the code-task fresh-evidence hard gate, and MEMORY keeps the conditional long-memory threshold
|
|
54
54
|
gate. The active task
|
|
55
|
-
pointer lives in `sessions/{
|
|
55
|
+
pointer lives in `sessions/{agent}-{session-id}.json` (with an agent-prefixed PPID fallback only
|
|
56
|
+
when a hook payload has no logical session ID);
|
|
56
57
|
when the task reaches `COMPLETE` or `CLOSED`, the state API clears `current_task` so the
|
|
57
58
|
session returns to Ready. Each task's stage persists in its `task.json`. Hooks inject the
|
|
58
59
|
session and task state as breadcrumbs so every reply can render the status line.
|
|
@@ -37,23 +37,27 @@ Python runtime files are shared verbatim across platforms (only the JSON wrapper
|
|
|
37
37
|
transitions, and task state reads.
|
|
38
38
|
- `easy_coding_status.py` — renders the Markdown status line and machine breadcrumbs from
|
|
39
39
|
state API snapshots.
|
|
40
|
-
- `session-start.py` —
|
|
41
|
-
|
|
42
|
-
- `inject-workflow-state.py` — injects the `workflow-state`
|
|
43
|
-
the status line can render.
|
|
40
|
+
- `session-start.py` — initializes the per-session file on native session-start events and emits
|
|
41
|
+
resume / init-required / handoff breadcrumbs.
|
|
42
|
+
- `inject-workflow-state.py` — idempotently ensures the session and injects the `workflow-state`
|
|
43
|
+
and `current-task` breadcrumbs so the status line can render.
|
|
44
44
|
- `inject-subagent-context.py` — injects the sub-agent guard before an Agent tool call.
|
|
45
45
|
|
|
46
46
|
Wrapper differences:
|
|
47
47
|
|
|
48
48
|
- **Claude Code**: full event set — `SessionStart`, `UserPromptSubmit`, `PreToolUse(Agent)`.
|
|
49
|
-
`session-start.py`
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- **Qoder**:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
`session-start.py` owns native session initialization, while `inject-workflow-state.py` is the
|
|
50
|
+
single session writer on each prompt.
|
|
51
|
+
- **Codex**: `session-start.py` runs on `SessionStart`, while
|
|
52
|
+
`inject-workflow-state.py` runs on `UserPromptSubmit`; `inject-subagent-context.py` is
|
|
53
|
+
skipped because Codex has no Agent tool hook. Codex hooks also require user-level enablement
|
|
54
|
+
(`[features] hooks = true`).
|
|
55
|
+
- **Qoder**: has no separate session-start registration, so `inject-workflow-state.py` performs
|
|
56
|
+
idempotent initialization and state injection as the single `UserPromptSubmit` writer. Qoder
|
|
57
|
+
also has Agent tool + Stop hooks, and `.qoder/settings.json` nests an extra `hooks` array.
|
|
58
|
+
|
|
59
|
+
Every session-writing hook resolves the same agent-prefixed logical session key from the hook
|
|
60
|
+
payload, for example `codex-<session-id>.json`. On first use it adopts a legacy `<ppid>.json`
|
|
61
|
+
file when present. A global atomic migration lock ensures only one concurrently starting session
|
|
62
|
+
can claim legacy `state.json`; the winner commits its canonical session before removing the old
|
|
63
|
+
state and releasing the lock.
|
|
@@ -28,21 +28,28 @@ with `.easy-coding/sessions/` always excluded. The CLI already added it to `.git
|
|
|
28
28
|
|
|
29
29
|
## Rules
|
|
30
30
|
|
|
31
|
-
1. **
|
|
32
|
-
warn: "Task «X» is not finished — commit the intermediate state?"
|
|
33
|
-
|
|
31
|
+
1. **Non-terminal warning.** If the commit touches a task folder whose status is neither
|
|
32
|
+
`COMPLETE` nor `CLOSED`, warn: "Task «X» is not finished — commit the intermediate state?"
|
|
33
|
+
and wait. `COMPLETE` and `CLOSED` are terminal states; include their task artifacts without
|
|
34
|
+
asking for intermediate-state confirmation.
|
|
35
|
+
2. **CLI-managed upgrade changes.** Inspect the complete workspace change list before choosing
|
|
36
|
+
the commit set. Changes written by `easy-coding upgrade` to managed harness files are in
|
|
37
|
+
scope by default. Do not exclude them because the current agent did not write them or
|
|
38
|
+
because they were produced outside the current assistant turn. Preserve the explicit path
|
|
39
|
+
exclusions above, and report unrelated pre-existing work separately.
|
|
40
|
+
3. **Conflict handling for `.easy-coding/`** (mostly `memory/`): first explain the conflict
|
|
34
41
|
details to the user, get confirmation, then do an inductive semantic merge — never blindly
|
|
35
42
|
pick ours/theirs. This requirement applies only to conflicts inside `.easy-coding/`.
|
|
36
|
-
|
|
43
|
+
4. **Cross-repo commit sets.** When a task spans repos (per the dev-spec / current task
|
|
37
44
|
`repo_paths`), the commit/push covers every involved repo. Read `repo_paths` from the
|
|
38
45
|
current task state to locate each checkout, check changes, and commit/push them as one
|
|
39
46
|
coherent change set — do not leave a sub-repo behind.
|
|
40
|
-
|
|
47
|
+
5. **Supermodule two-step commits.** If the current repo has `.gitmodules`, or the current
|
|
41
48
|
task touches a git submodule path, treat each submodule as an independent git boundary:
|
|
42
49
|
commit and push child repos first, then commit and push the parent gitlink update. If a
|
|
43
50
|
child repo is on a detached HEAD, stop and ask the user to choose or create a branch before
|
|
44
51
|
committing there.
|
|
45
|
-
|
|
52
|
+
6. **No false success.** Never claim a commit or push succeeded without reading the command
|
|
46
53
|
output. A failed push reported as success is a serious error.
|
|
47
54
|
|
|
48
55
|
## Boundaries
|
|
@@ -50,6 +57,8 @@ with `.easy-coding/sessions/` always excluded. The CLI already added it to `.git
|
|
|
50
57
|
- Do not touch session files, task status fields, or run stage transitions — git only.
|
|
51
58
|
- Do not commit `.easy-coding/sessions/`.
|
|
52
59
|
- Do not commit `spec/dev/` unless the user explicitly asks.
|
|
60
|
+
- Do not omit managed `easy-coding upgrade` changes merely because they were created outside
|
|
61
|
+
the current agent turn.
|
|
53
62
|
- In a supermodule task launched from the parent root, parent `.easy-coding/` belongs to the
|
|
54
63
|
parent git. Child `.easy-coding/memory/` changes created by memory archive belong to the
|
|
55
64
|
owning child git and must be committed before the parent gitlink update.
|
|
@@ -18,13 +18,17 @@ recorded comment/doc language.
|
|
|
18
18
|
|
|
19
19
|
Create one file under `.easy-coding/memory/short/` following the format in
|
|
20
20
|
`.easy-coding/memory/SHORT_MEMORY_TEMPLATE.md`. File naming convention:
|
|
21
|
-
`{
|
|
21
|
+
`{memory_id}_{YYYYMMDD}_{smart_name}.md`. Generate the id first with
|
|
22
|
+
`{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py memory-new-id --session-file <P> --agent <agent-id>`.
|
|
23
|
+
Use the returned `memory_id` unchanged as both the filename prefix and the frontmatter `id`.
|
|
24
|
+
It uses UUIDv7, so agents never scan the directory or calculate a shared numeric sequence.
|
|
25
|
+
Keep the readable `smart_name` suffix. The entry is immutable after creation.
|
|
22
26
|
Frontmatter (all fields required):
|
|
23
27
|
|
|
24
28
|
```yaml
|
|
25
29
|
---
|
|
26
30
|
memory_schema: 2
|
|
27
|
-
id:
|
|
31
|
+
id: {memory_id returned by memory-new-id, exact}
|
|
28
32
|
source_task: {current task id, exact}
|
|
29
33
|
date: {YYYY-MM-DD}
|
|
30
34
|
task_type: {feature | bugfix | refactor | perf | doc | workflow}
|
|
@@ -53,7 +57,8 @@ After the file is successfully written, record the checkpoint immediately:
|
|
|
53
57
|
Use the returned `status_context` as authoritative. On resume, if `memory_progress` already
|
|
54
58
|
shows `short_memory_written:true`, do not create a duplicate entry; continue from Step 2.
|
|
55
59
|
The state API validates `memory_schema: 2`, requires `source_task` to equal the current task id,
|
|
56
|
-
|
|
60
|
+
requires a UUIDv7 id that exactly matches the filename prefix, and fingerprints the file. Do not
|
|
61
|
+
reuse an older task's memory file as this checkpoint.
|
|
57
62
|
|
|
58
63
|
## Supermodule memory routing
|
|
59
64
|
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"hooks": {
|
|
3
3
|
"UserPromptSubmit": [
|
|
4
|
-
{
|
|
5
|
-
"hooks": [
|
|
6
|
-
{
|
|
7
|
-
"type": "command",
|
|
8
|
-
"command": "{{platform_hook_session_start_command}}",
|
|
9
|
-
"timeout": 10
|
|
10
|
-
}
|
|
11
|
-
]
|
|
12
|
-
},
|
|
13
4
|
{
|
|
14
5
|
"hooks": [
|
|
15
6
|
{
|
|
16
7
|
"type": "command",
|
|
17
8
|
"command": "{{platform_hook_inject_workflow_state_command}}",
|
|
18
|
-
"timeout":
|
|
9
|
+
"timeout": 10
|
|
19
10
|
}
|
|
20
11
|
]
|
|
21
12
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
memory_schema: 2
|
|
3
|
-
id:
|
|
3
|
+
id: {memory_id}
|
|
4
4
|
source_task: MM-DD-task-slug
|
|
5
5
|
date: YYYY-MM-DD
|
|
6
6
|
task_type: feature | bugfix | refactor | perf | doc | workflow
|
|
@@ -20,14 +20,17 @@ target_long: BUSINESS | TECHNICAL | BOTH | NONE
|
|
|
20
20
|
# Short Memory Template
|
|
21
21
|
|
|
22
22
|
> This template defines the format for files under `.easy-coding/memory/short/`.
|
|
23
|
-
> File naming convention: `{
|
|
23
|
+
> File naming convention: `{memory_id}_{YYYYMMDD}_{smart_name}.md`
|
|
24
|
+
> Generate `memory_id` through the state API `memory-new-id` command and use it unchanged as
|
|
25
|
+
> both the filename prefix and this frontmatter `id`. The UUIDv7 id is safe for concurrent agents.
|
|
26
|
+
> Keep `smart_name` as the readable summary suffix.
|
|
24
27
|
> `source_task` must exactly match the current workflow task id from `task.json`.
|
|
25
28
|
> Short memories are immutable after creation — they serve as a sliding window of recent
|
|
26
29
|
> details and a buffer for long-term distillation candidates.
|
|
27
30
|
> When short memories reach the threshold (default 10), the newest 5 are kept as recent
|
|
28
31
|
> context; older entries are distillation candidates for long-term memory.
|
|
29
|
-
> Sorting: by frontmatter `date` ascending
|
|
30
|
-
>
|
|
32
|
+
> Sorting: by frontmatter `date` ascending, then by frontmatter `id`, then by filename. Legacy
|
|
33
|
+
> `SM-YYYYMMDD-NNN` ids sort before UUIDv7 ids on the same date for upgrade compatibility.
|
|
31
34
|
|
|
32
35
|
## Task Summary
|
|
33
36
|
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
- **核心类 / 页面 / 接口**:[[EC_TODO:核心类 / 页面 / 接口]]
|
|
30
30
|
- **数据库变更**:[[EC_TODO:有/无]]
|
|
31
31
|
- **接口变更**:[[EC_TODO:有/无]]
|
|
32
|
-
- **关联历史任务**:[[EC_TODO
|
|
32
|
+
- **关联历史任务**:[[EC_TODO:相关短期记忆 ID;无则“无”]]
|
|
33
33
|
|
|
34
34
|
### 改动范围
|
|
35
35
|
> 只列真实项目源码/配置文件的改动。禁止把 `.easy-coding/` 下的 harness 产物(dev-spec / execution.jsonl / test-strategy / 记忆 / 报告等)当作改动对象。本表为空仅允许用于"用户明确要求的无代码交付形态";代码类任务(重构/修复/功能)若此表为空,即为自我降级。
|