easy-coding-harness 0.5.2-beta.0 → 0.5.3

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 CHANGED
@@ -6,6 +6,13 @@
6
6
  - `y`:常规功能升级
7
7
  - `z`:日常 bug 修复
8
8
 
9
+ ## 0.5.3
10
+
11
+ - 根治 `task.json` 绝对路径泄漏:`.easy-coding/tasks/project-init/task.json` 不再写入本机仓库绝对路径。该 `project_path` 字段无任何消费方,直接移除,可提交产物彻底去本地化。
12
+ - `easy-coding upgrade` 会自动剥离存量项目中遗留的 `project_path` 字段,让老项目也随升级变干净。
13
+ - 根治 hook 编译产物:hook launcher 设置 `sys.dont_write_bytecode=True`,运行时不再在 `.claude/hooks/`、`.codex/hooks/`、`.qoder/hooks/` 旁生成 `__pycache__/*.pyc`;同时 `init` / `add-agent` / `upgrade` 会向项目 `.gitignore` 追加 `__pycache__/` 作为兜底防御。launcher 内容变化会触发 `upgrade` 刷新存量 hook 注册。
14
+ - 版本自 `0.5.2-beta.0` 升级为 `0.5.3`,合并 beta.0 的全部 portable hook 修复。跳过 `0.5.2` 正式版:升级检测的 `compareVersions` 会截断预发布后缀,若发 `0.5.2` 会把已安装 `0.5.2-beta.0` 的项目误判为已最新而不提示本次迁移;递增到 `0.5.3` 可让 beta 用户正确检测到升级。
15
+
9
16
  ## 0.5.2-beta.0
10
17
 
11
18
  - 修复 Claude Code hook 命令使用直接相对路径导致在子目录 cwd 下找不到 `.claude/hooks/*.py` 的问题;Claude、Codex、Qoder 的 hook 配置现在使用可共享的 portable relative launcher,并绑定 `.easy-coding/config.yaml` 的 `project.id`,避免把本机仓库绝对路径写入可提交配置,同时防止 supermodule 父仓 hook 被子仓 cwd 错路由。
package/dist/cli.js CHANGED
@@ -208,6 +208,7 @@ var MAIN_SPEC_DIR = "main";
208
208
  var DEV_SPEC_DIR = "dev";
209
209
  var TEMPLATES_DIR = "templates";
210
210
  var SESSIONS_GITIGNORE_ENTRY = ".easy-coding/sessions/";
211
+ var HOOK_BYTECODE_GITIGNORE_ENTRY = "__pycache__/";
211
212
  var GENERATED_REGION_START = "<!-- \u2550\u2550\u2550 easy-coding-harness generated (DO NOT EDIT BETWEEN MARKERS) \u2550\u2550\u2550 -->";
212
213
  var GENERATED_REGION_END = "<!-- \u2550\u2550\u2550 end easy-coding-harness generated \u2550\u2550\u2550 -->";
213
214
 
@@ -227,6 +228,13 @@ async function ensureGitignoreEntry(cwd, entry, heading = "# \u2550\u2550\u2550
227
228
  async function ensureEasyCodingSessionsIgnored(cwd) {
228
229
  return ensureGitignoreEntry(cwd, SESSIONS_GITIGNORE_ENTRY);
229
230
  }
231
+ async function ensureHookBytecodeIgnored(cwd) {
232
+ return ensureGitignoreEntry(
233
+ cwd,
234
+ HOOK_BYTECODE_GITIGNORE_ENTRY,
235
+ "# \u2550\u2550\u2550 easy-coding-harness (auto-generated) \u2550\u2550\u2550\n# Python bytecode from hook scripts; do not commit"
236
+ );
237
+ }
230
238
 
231
239
  // src/utils/install-manifest.ts
232
240
  import { createHash } from "crypto";
@@ -658,7 +666,6 @@ function createProjectInitTask(params) {
658
666
  context: {
659
667
  agents_installed: params.agents,
660
668
  cli_version: VERSION,
661
- project_path: params.cwd,
662
669
  init_source: params.initSource ?? "fresh",
663
670
  ...params.legacyAssets ? { legacy_assets: params.legacyAssets } : {},
664
671
  ...params.legacyMissingHarnessFiles ? { legacy_missing_harness_files: params.legacyMissingHarnessFiles } : {}
@@ -679,7 +686,6 @@ async function writeProjectInitTask(cwd, agents, options = {}) {
679
686
  await writeTaskJson(
680
687
  getTaskJsonPath(cwd, PROJECT_INIT_TASK_ID),
681
688
  createProjectInitTask({
682
- cwd,
683
689
  agents,
684
690
  initSource: options.initSource,
685
691
  legacyAssets: options.legacyAssets,
@@ -687,6 +693,15 @@ async function writeProjectInitTask(cwd, agents, options = {}) {
687
693
  })
688
694
  );
689
695
  }
696
+ async function stripInitTaskProjectPath(cwd) {
697
+ const filePath = getTaskJsonPath(cwd, PROJECT_INIT_TASK_ID);
698
+ if (!await pathExists(filePath)) return false;
699
+ const task = await readTaskJson(filePath);
700
+ if (!task.context || !("project_path" in task.context)) return false;
701
+ task.context.project_path = void 0;
702
+ await writeTaskJson(filePath, task);
703
+ return true;
704
+ }
690
705
  async function setPendingInitSince(cwd, version) {
691
706
  const filePath = getTaskJsonPath(cwd, PROJECT_INIT_TASK_ID);
692
707
  if (!await pathExists(filePath)) return;
@@ -830,6 +845,7 @@ function jsonStringContent(value) {
830
845
  }
831
846
  var HOOK_LAUNCHER_PYTHON = [
832
847
  "import io,json,os,re,runpy,sys",
848
+ "sys.dont_write_bytecode=True",
833
849
  "from pathlib import Path",
834
850
  "payload=sys.stdin.read()",
835
851
  "try:",
@@ -1264,6 +1280,7 @@ async function installHarnessToDir(targetDir, platforms, ctx) {
1264
1280
  legacyMissingHarnessFiles: ctx.legacyMissingHarnessFiles
1265
1281
  });
1266
1282
  await ensureEasyCodingSessionsIgnored(targetDir);
1283
+ await ensureHookBytecodeIgnored(targetDir);
1267
1284
  return artifacts;
1268
1285
  }
1269
1286
  function supermoduleConfigFromContext(ctx) {
@@ -1759,6 +1776,7 @@ async function addAgent(opts) {
1759
1776
  mode: "merge"
1760
1777
  });
1761
1778
  await ensureEasyCodingSessionsIgnored(target.dir);
1779
+ await ensureHookBytecodeIgnored(target.dir);
1762
1780
  await addAgentsToConfig(target.configPath, toInstall);
1763
1781
  await setPendingInitSince(target.dir, VERSION);
1764
1782
  installedLabels.push(`${target.label}: ${toInstall.join(", ")}`);
@@ -2861,9 +2879,11 @@ async function upgrade(opts) {
2861
2879
  artifacts
2862
2880
  });
2863
2881
  await ensureEasyCodingSessionsIgnored(target.dir);
2882
+ await ensureHookBytecodeIgnored(target.dir);
2864
2883
  await updateHarnessVersion(target.configPath, VERSION);
2865
2884
  await updateSupermoduleConfig(target.configPath, target.supermodule);
2866
2885
  await setPendingInitSince(target.dir, VERSION);
2886
+ await stripInitTaskProjectPath(target.dir);
2867
2887
  }
2868
2888
  if (parentTopologyRefresh) {
2869
2889
  await refreshSupermoduleParent(