easy-coding-harness 0.10.0-beta.8 → 0.10.0-beta.9
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 +16 -0
- package/dist/cli.js +94 -4
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/common/skills/ec-implementing/SKILL.md +3 -1
- package/templates/common/skills/ec-workflow/SKILL.md +3 -0
- package/templates/main-constraint/AGENTS.md.tpl +8 -2
- package/templates/main-constraint/CLAUDE.md.tpl +5 -2
- package/templates/shared-hooks/easy_coding_state.py +131 -17
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@
|
|
|
6
6
|
- `y`:常规功能升级
|
|
7
7
|
- `z`:日常 bug 修复
|
|
8
8
|
|
|
9
|
+
## 0.10.0-beta.9
|
|
10
|
+
|
|
11
|
+
- 工作流 owner 改为规范平台身份边界:每份安装后的状态脚本固化宿主身份,新写入只接受
|
|
12
|
+
`claude-code` / `codex` / `qoder`,脚本身份、`--agent` 与已注入 session 命名空间三方
|
|
13
|
+
不一致时在落盘前拒绝;`Codex with Easy Coding` 等作者/Canonical 展示归属不再允许进入
|
|
14
|
+
`last_agent`。
|
|
15
|
+
- Codex 与 Qoder 共用的 `AGENTS.md` 生成区改为安装顺序无关的双平台路径合同,
|
|
16
|
+
明确当前宿主只能调用自己的状态脚本,防止 Qoder 最后写入后误导 Codex 执行
|
|
17
|
+
`.qoder/hooks/easy_coding_state.py`。
|
|
18
|
+
- handoff 提示改为显式协调事件驱动:只有未消费的 `handoff` 记录才显示交接,
|
|
19
|
+
`claim-task` 新增 immutable `claim` 审计记录并关闭交接;单纯 owner 差异不再被伪造成
|
|
20
|
+
handoff。
|
|
21
|
+
- upgrade 与首次 SessionStart 幂等迁移旧任务/session 中的 `root` 系列和误写展示名,
|
|
22
|
+
即使版本号已经更新也能继续检测并自愈,但保留 `execution.jsonl` 及 Canonical Spec 的
|
|
23
|
+
历史审计展示;新增生产形态、跨平台路径冲突、安装顺序和真实 handoff/claim 回归测试。
|
|
24
|
+
|
|
9
25
|
## 0.10.0-beta.8
|
|
10
26
|
|
|
11
27
|
- VERIFICATION 绿色后新增可审计验收检查点。无漂移时 `confirm` / `auto` 继续按原审批模式
|
package/dist/cli.js
CHANGED
|
@@ -311,6 +311,7 @@ var PLATFORM_META = {
|
|
|
311
311
|
stateInjectEvent: ["SessionStart", "UserPromptSubmit"],
|
|
312
312
|
hasSubagentContext: true,
|
|
313
313
|
templateContext: {
|
|
314
|
+
workflow_agent_id: "claude-code",
|
|
314
315
|
sub_agent_dispatch: "Agent tool",
|
|
315
316
|
platform_spawn_instruction: 'Use the Agent tool with run_in_background when useful; use isolation: "worktree" for parallel file edits.',
|
|
316
317
|
skill_trigger: "/",
|
|
@@ -334,6 +335,7 @@ var PLATFORM_META = {
|
|
|
334
335
|
stateInjectEvent: ["SessionStart", "UserPromptSubmit"],
|
|
335
336
|
hasSubagentContext: false,
|
|
336
337
|
templateContext: {
|
|
338
|
+
workflow_agent_id: "codex",
|
|
337
339
|
sub_agent_dispatch: "Codex sub-agent dispatch",
|
|
338
340
|
platform_spawn_instruction: "Use Codex sub-agent delegation where available; pass the full task card in the prompt.",
|
|
339
341
|
skill_trigger: "$",
|
|
@@ -358,6 +360,7 @@ var PLATFORM_META = {
|
|
|
358
360
|
hasSubagentContext: true,
|
|
359
361
|
cnVariant: ".qodercn",
|
|
360
362
|
templateContext: {
|
|
363
|
+
workflow_agent_id: "qoder",
|
|
361
364
|
sub_agent_dispatch: "Agent tool",
|
|
362
365
|
platform_spawn_instruction: "Use the Agent tool with worktree isolation for parallel file edits.",
|
|
363
366
|
skill_trigger: "/",
|
|
@@ -776,6 +779,87 @@ function isLegacyStage(value) {
|
|
|
776
779
|
function migrateStage(value) {
|
|
777
780
|
return isLegacyStage(value) ? LEGACY_STAGE_MAP[value] : value;
|
|
778
781
|
}
|
|
782
|
+
var LEGACY_DISPLAY_AGENT_IDENTITIES = {
|
|
783
|
+
"claude with easy coding": "claude-code",
|
|
784
|
+
"claude-code with easy coding": "claude-code",
|
|
785
|
+
"claude code with easy coding": "claude-code",
|
|
786
|
+
"codex with easy coding": "codex",
|
|
787
|
+
"qoder with easy coding": "qoder"
|
|
788
|
+
};
|
|
789
|
+
function migratedAgentIdentity(value) {
|
|
790
|
+
if (typeof value !== "string") return void 0;
|
|
791
|
+
const normalized = value.trim().toLowerCase();
|
|
792
|
+
if (normalized === "claude-code" || normalized === "codex" || normalized === "qoder") {
|
|
793
|
+
return normalized;
|
|
794
|
+
}
|
|
795
|
+
if (/^\/?root(?:\/[a-z0-9._-]+)*$/.test(normalized)) return "codex";
|
|
796
|
+
return LEGACY_DISPLAY_AGENT_IDENTITIES[normalized];
|
|
797
|
+
}
|
|
798
|
+
function migrateAgentFields(record, fields) {
|
|
799
|
+
let changed = false;
|
|
800
|
+
for (const field of fields) {
|
|
801
|
+
const migrated = migratedAgentIdentity(record[field]);
|
|
802
|
+
if (migrated && migrated !== record[field]) {
|
|
803
|
+
record[field] = migrated;
|
|
804
|
+
changed = true;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
return changed;
|
|
808
|
+
}
|
|
809
|
+
function taskAgentFieldGroups(task) {
|
|
810
|
+
const groups = [
|
|
811
|
+
{
|
|
812
|
+
record: task,
|
|
813
|
+
fields: ["created_by", "last_agent", "workflow_mode_confirmed_by", "tdd_confirmed_by"]
|
|
814
|
+
}
|
|
815
|
+
];
|
|
816
|
+
for (const field of ["pending_transition", "workflow_mode_proposal", "verification_checkpoint"]) {
|
|
817
|
+
const value = task[field];
|
|
818
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
819
|
+
const identityField = field === "pending_transition" ? "requested_by" : field === "workflow_mode_proposal" ? "proposed_by" : "recorded_by";
|
|
820
|
+
groups.push({ record: value, fields: [identityField] });
|
|
821
|
+
}
|
|
822
|
+
if (Array.isArray(task.workflow_mode_escalations)) {
|
|
823
|
+
for (const escalation of task.workflow_mode_escalations) {
|
|
824
|
+
if (!escalation || typeof escalation !== "object" || Array.isArray(escalation)) continue;
|
|
825
|
+
groups.push({ record: escalation, fields: ["raised_by"] });
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
const memoryProgress = task.memory_progress;
|
|
829
|
+
if (memoryProgress && typeof memoryProgress === "object" && !Array.isArray(memoryProgress)) {
|
|
830
|
+
const assessment = memoryProgress.architecture_assessment;
|
|
831
|
+
if (assessment && typeof assessment === "object" && !Array.isArray(assessment)) {
|
|
832
|
+
groups.push({ record: assessment, fields: ["recorded_by"] });
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (Array.isArray(task.spec_dependency_evidence)) {
|
|
836
|
+
for (const evidence of task.spec_dependency_evidence) {
|
|
837
|
+
if (!evidence || typeof evidence !== "object" || Array.isArray(evidence)) continue;
|
|
838
|
+
groups.push({ record: evidence, fields: ["satisfied_by"] });
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
if (Array.isArray(task.stage_history)) {
|
|
842
|
+
for (const entry of task.stage_history) {
|
|
843
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
844
|
+
groups.push({ record: entry, fields: ["agent"] });
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return groups;
|
|
848
|
+
}
|
|
849
|
+
function migrateTaskAgentIdentities(task) {
|
|
850
|
+
return taskAgentFieldGroups(task).reduce(
|
|
851
|
+
(changed, group) => migrateAgentFields(group.record, group.fields) || changed,
|
|
852
|
+
false
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
function hasLegacyTaskAgentIdentities(task) {
|
|
856
|
+
return taskAgentFieldGroups(task).some(
|
|
857
|
+
({ record, fields }) => fields.some((field) => {
|
|
858
|
+
const migrated = migratedAgentIdentity(record[field]);
|
|
859
|
+
return migrated !== void 0 && migrated !== record[field];
|
|
860
|
+
})
|
|
861
|
+
);
|
|
862
|
+
}
|
|
779
863
|
function migrateStageHistory(task) {
|
|
780
864
|
if (!Array.isArray(task.stage_history)) return false;
|
|
781
865
|
let changed = false;
|
|
@@ -806,7 +890,8 @@ function migrateTaskWorkflowState(task) {
|
|
|
806
890
|
const legacyRequestedAt = Array.isArray(task.stage_history) ? [...task.stage_history].reverse().find(
|
|
807
891
|
(entry) => entry && typeof entry === "object" && !Array.isArray(entry) && entry.stage === "WAITING_CONFIRM"
|
|
808
892
|
) : null;
|
|
809
|
-
let changed =
|
|
893
|
+
let changed = migrateTaskAgentIdentities(task);
|
|
894
|
+
changed = migrateStageHistory(task) || changed;
|
|
810
895
|
if (legacyStatus) {
|
|
811
896
|
task.status = LEGACY_STAGE_MAP[legacyStatus];
|
|
812
897
|
changed = true;
|
|
@@ -858,7 +943,7 @@ function migrateTaskWorkflowState(task) {
|
|
|
858
943
|
return changed;
|
|
859
944
|
}
|
|
860
945
|
function migrateSessionBehavior(session) {
|
|
861
|
-
let changed =
|
|
946
|
+
let changed = migrateAgentFields(session, ["agent", "last_agent"]);
|
|
862
947
|
const legacyMode = session.confirm_mode;
|
|
863
948
|
const legacyLite = legacyMode === "lite";
|
|
864
949
|
if (!["approve", "guard", "confirm", "auto"].includes(String(session.approval_mode ?? ""))) {
|
|
@@ -969,7 +1054,7 @@ async function hasLegacyWorkflowState(cwd) {
|
|
|
969
1054
|
if (!await pathExists(filePath)) continue;
|
|
970
1055
|
const task = await readJsonRecord(filePath);
|
|
971
1056
|
if (!task) continue;
|
|
972
|
-
if (isLegacyStage(task.status) || !["PENDING", "COMPLETE", "CLOSED"].includes(String(task.status ?? "")) && String(task.type ?? "") !== "project-init" && !["fast", "standard", "strict"].includes(String(task.workflow_mode ?? "")) || Array.isArray(task.stage_history) && task.stage_history.some(
|
|
1057
|
+
if (hasLegacyTaskAgentIdentities(task) || isLegacyStage(task.status) || !["PENDING", "COMPLETE", "CLOSED"].includes(String(task.status ?? "")) && String(task.type ?? "") !== "project-init" && !["fast", "standard", "strict"].includes(String(task.workflow_mode ?? "")) || Array.isArray(task.stage_history) && task.stage_history.some(
|
|
973
1058
|
(entry) => entry && typeof entry === "object" && !Array.isArray(entry) && isLegacyStage(entry.stage)
|
|
974
1059
|
)) {
|
|
975
1060
|
return true;
|
|
@@ -978,7 +1063,12 @@ async function hasLegacyWorkflowState(cwd) {
|
|
|
978
1063
|
for (const filePath of await sessionFiles(cwd)) {
|
|
979
1064
|
const session = await readJsonRecord(filePath);
|
|
980
1065
|
if (!session) continue;
|
|
981
|
-
if (
|
|
1066
|
+
if (["agent", "last_agent"].some((field) => {
|
|
1067
|
+
const migrated = migratedAgentIdentity(session[field]);
|
|
1068
|
+
return migrated !== void 0 && migrated !== session[field];
|
|
1069
|
+
}) || isLegacyStage(session.last_seen_stage) || "confirm_mode" in session) {
|
|
1070
|
+
return true;
|
|
1071
|
+
}
|
|
982
1072
|
}
|
|
983
1073
|
return false;
|
|
984
1074
|
}
|