@pennixrv/trellis 0.7.0-beta.51 → 0.7.0-beta.52

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.
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": "0.7.0-beta.52",
3
+ "description": "修复日期任务的交接围栏,并拒绝携带正式 ownership 记录的任务改名",
4
+ "breaking": false,
5
+ "recommendMigrate": false,
6
+ "changelog": "交接围栏使用 task.json 中的规范任务 ID 查询记录,覆盖原生日期目录;任何正式 ownership 记录均阻止任务改名,避免留下失效的路径和身份引用。",
7
+ "migrations": [],
8
+ "notes": "无任务 schema、ownership 记录格式或历史迁移。没有正式 ownership 存储的普通任务保留原行为;已有交接记录的任务需保持原名。"
9
+ }
@@ -416,20 +416,35 @@ def status(root: Path | None, task_id: str, handoff_id: str, core_digest: str) -
416
416
  return _public(record)
417
417
 
418
418
 
419
+ def _task_ownership_records(root: Path, task_path: Path) -> tuple[dict[str, str], list[Path]]:
420
+ """Discover records by validated JSON identity, never by directory name."""
421
+ runtime = root / ".trellis" / ".runtime"
422
+ ownership = runtime / "handoff-ownership"
423
+ if runtime.is_symlink() or ownership.is_symlink():
424
+ raise OwnershipError("ownership record directory is unsafe")
425
+ if not ownership.exists():
426
+ return {}, []
427
+ relative = task_path.relative_to(root).as_posix()
428
+ try:
429
+ task = _task_snapshot(root, relative)
430
+ records_dir = _record_path(root, task["id"], "record-probe").parent
431
+ except ContinuationError as exc:
432
+ raise OwnershipError(str(exc)) from exc
433
+ return task, sorted(records_dir.glob("*.json"))
434
+
435
+
436
+ def assert_task_rename_allowed(root: Path, task_path: Path) -> None:
437
+ """A rename cannot preserve the immutable identity of a formal handoff."""
438
+ _task, records = _task_ownership_records(root, task_path)
439
+ if records:
440
+ raise OwnershipError("refusing rename: task has formal handoff ownership records")
441
+
442
+
419
443
  def assert_task_mutation_allowed(root: Path, task_path: Path) -> None:
420
444
  """Reject ordinary task pointer changes that would bypass ownership fencing."""
445
+ task, records = _task_ownership_records(root, task_path)
421
446
  actor = resolve_context_key()
422
- try:
423
- task_id = _safe_task_id(task_path.name)
424
- except ContinuationError:
425
- return
426
- relative = task_path.relative_to(root).as_posix()
427
- records_dir = root / ".trellis" / ".runtime" / "handoff-ownership" / task_id
428
- if records_dir.is_symlink():
429
- raise OwnershipError("ownership record directory is unsafe")
430
- if not records_dir.is_dir():
431
- return
432
- for record_path in sorted(records_dir.glob("*.json")):
447
+ for record_path in records:
433
448
  if not actor:
434
449
  raise OwnershipError("no_direct_session_identity: task has handoff ownership fencing")
435
450
  if record_path.is_symlink():
@@ -437,7 +452,7 @@ def assert_task_mutation_allowed(root: Path, task_path: Path) -> None:
437
452
  record = _decode(record_path)
438
453
  if record["state"] not in STATES:
439
454
  continue
440
- if record["task"]["path"] != relative:
455
+ if record["task"]["path"] != task["path"] or record["task"]["id"] != task["id"]:
441
456
  raise OwnershipError("ownership record task path does not match current task")
442
457
  if record.get("consumer_session_id") == actor:
443
458
  continue
@@ -1095,6 +1095,13 @@ def cmd_rename(args: argparse.Namespace) -> int:
1095
1095
  )
1096
1096
  return 1
1097
1097
 
1098
+ from .ownership_record import assert_task_rename_allowed
1099
+ try:
1100
+ assert_task_rename_allowed(repo_root, task_dir)
1101
+ except (OSError, ValueError) as exc:
1102
+ print(colored(f"Error: {exc}", Colors.RED), file=sys.stderr)
1103
+ return 1
1104
+
1098
1105
  old_name = task_dir.name
1099
1106
  date_prefix, _old_slug = _split_date_prefix(old_name)
1100
1107
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pennixrv/trellis",
3
- "version": "0.7.0-beta.51",
3
+ "version": "0.7.0-beta.52",
4
4
  "description": "AI capabilities grow like ivy — Trellis provides the structure to guide them along a disciplined path",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -34,7 +34,7 @@
34
34
  "inquirer": "^9.3.7",
35
35
  "undici": "^6.21.0",
36
36
  "zod": "^4.4.2",
37
- "@pennixrv/trellis-core": "0.7.0-beta.51"
37
+ "@pennixrv/trellis-core": "0.7.0-beta.52"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@eslint/js": "^9.18.0",