@mc-and-his-agents/loom-installer 0.1.21 → 0.1.23

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.
Files changed (52) hide show
  1. package/package.json +1 -1
  2. package/payload/manifest.json +102 -102
  3. package/payload/plugin/loom/skills/shared/scripts/governance_surface.py +57 -14
  4. package/payload/plugin/loom/skills/shared/scripts/loom_check.py +87 -0
  5. package/payload/plugin/loom/skills/shared/scripts/loom_flow.py +9 -6
  6. package/payload/plugin/loom/skills/shared/scripts/loom_init.py +57 -50
  7. package/payload/plugin/loom/skills/shared/scripts/runtime_state.py +17 -0
  8. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/governance_surface.py +57 -14
  9. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +87 -0
  10. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_flow.py +9 -6
  11. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_init.py +57 -50
  12. package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/runtime_state.py +17 -0
  13. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/governance_surface.py +57 -14
  14. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +87 -0
  15. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_flow.py +9 -6
  16. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_init.py +57 -50
  17. package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/runtime_state.py +17 -0
  18. package/payload/skills/loom-init/.loom-runtime/shared/scripts/governance_surface.py +57 -14
  19. package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +87 -0
  20. package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_flow.py +9 -6
  21. package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_init.py +57 -50
  22. package/payload/skills/loom-init/.loom-runtime/shared/scripts/runtime_state.py +17 -0
  23. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/governance_surface.py +57 -14
  24. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +87 -0
  25. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_flow.py +9 -6
  26. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_init.py +57 -50
  27. package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/runtime_state.py +17 -0
  28. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/governance_surface.py +57 -14
  29. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +87 -0
  30. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_flow.py +9 -6
  31. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_init.py +57 -50
  32. package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/runtime_state.py +17 -0
  33. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/governance_surface.py +57 -14
  34. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +87 -0
  35. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_flow.py +9 -6
  36. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_init.py +57 -50
  37. package/payload/skills/loom-resume/.loom-runtime/shared/scripts/runtime_state.py +17 -0
  38. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/governance_surface.py +57 -14
  39. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +87 -0
  40. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_flow.py +9 -6
  41. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_init.py +57 -50
  42. package/payload/skills/loom-retire/.loom-runtime/shared/scripts/runtime_state.py +17 -0
  43. package/payload/skills/loom-review/.loom-runtime/shared/scripts/governance_surface.py +57 -14
  44. package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +87 -0
  45. package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_flow.py +9 -6
  46. package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_init.py +57 -50
  47. package/payload/skills/loom-review/.loom-runtime/shared/scripts/runtime_state.py +17 -0
  48. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/governance_surface.py +57 -14
  49. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +87 -0
  50. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_flow.py +9 -6
  51. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_init.py +57 -50
  52. package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/runtime_state.py +17 -0
@@ -4,6 +4,7 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import argparse
7
+ import hashlib
7
8
  import json
8
9
  import os
9
10
  import re
@@ -27,6 +28,17 @@ TOOL_VERSION = "1.3.0"
27
28
  CONTRACT_VERSION = "1.3.0"
28
29
  WORK_ITEM_ID = "INIT-0001"
29
30
 
31
+ RUNTIME_ARTIFACT_SOURCES = {
32
+ ".loom/bin/loom_init.py": RUNTIME_SOURCE,
33
+ ".loom/bin/fact_chain_support.py": FACT_CHAIN_RUNTIME_SOURCE,
34
+ ".loom/bin/governance_surface.py": GOVERNANCE_RUNTIME_SOURCE,
35
+ ".loom/bin/loom_flow.py": FLOW_RUNTIME_SOURCE,
36
+ ".loom/bin/loom_status.py": STATUS_RUNTIME_SOURCE,
37
+ ".loom/bin/runtime_paths.py": "skills/shared/scripts/runtime_paths.py",
38
+ ".loom/bin/runtime_state.py": "skills/shared/scripts/runtime_state.py",
39
+ ".loom/bin/loom_check.py": CHECK_RUNTIME_SOURCE,
40
+ }
41
+
30
42
  ROOT_BOUNDARY_FILES = (
31
43
  "AGENTS.md",
32
44
  "WORKFLOW.md",
@@ -816,46 +828,14 @@ def initial_artifacts(target_root: Path, install_pr_template: bool, adoption_pat
816
828
  "kind": "capability-map",
817
829
  "source": "generated",
818
830
  },
819
- {
820
- "path": ".loom/bin/loom_init.py",
821
- "kind": "loom-tool",
822
- "source": RUNTIME_SOURCE,
823
- },
824
- {
825
- "path": ".loom/bin/fact_chain_support.py",
826
- "kind": "loom-tool-support",
827
- "source": FACT_CHAIN_RUNTIME_SOURCE,
828
- },
829
- {
830
- "path": ".loom/bin/governance_surface.py",
831
- "kind": "loom-tool-support",
832
- "source": GOVERNANCE_RUNTIME_SOURCE,
833
- },
834
- {
835
- "path": ".loom/bin/loom_flow.py",
836
- "kind": "loom-tool",
837
- "source": FLOW_RUNTIME_SOURCE,
838
- },
839
- {
840
- "path": ".loom/bin/loom_status.py",
841
- "kind": "loom-tool",
842
- "source": STATUS_RUNTIME_SOURCE,
843
- },
844
- {
845
- "path": ".loom/bin/runtime_paths.py",
846
- "kind": "loom-tool-support",
847
- "source": "skills/shared/scripts/runtime_paths.py",
848
- },
849
- {
850
- "path": ".loom/bin/runtime_state.py",
851
- "kind": "loom-tool-support",
852
- "source": "skills/shared/scripts/runtime_state.py",
853
- },
854
- {
855
- "path": ".loom/bin/loom_check.py",
856
- "kind": "loom-tool",
857
- "source": CHECK_RUNTIME_SOURCE,
858
- },
831
+ runtime_artifact(".loom/bin/loom_init.py", "loom-tool", RUNTIME_SOURCE),
832
+ runtime_artifact(".loom/bin/fact_chain_support.py", "loom-tool-support", FACT_CHAIN_RUNTIME_SOURCE),
833
+ runtime_artifact(".loom/bin/governance_surface.py", "loom-tool-support", GOVERNANCE_RUNTIME_SOURCE),
834
+ runtime_artifact(".loom/bin/loom_flow.py", "loom-tool", FLOW_RUNTIME_SOURCE),
835
+ runtime_artifact(".loom/bin/loom_status.py", "loom-tool", STATUS_RUNTIME_SOURCE),
836
+ runtime_artifact(".loom/bin/runtime_paths.py", "loom-tool-support", "skills/shared/scripts/runtime_paths.py"),
837
+ runtime_artifact(".loom/bin/runtime_state.py", "loom-tool-support", "skills/shared/scripts/runtime_state.py"),
838
+ runtime_artifact(".loom/bin/loom_check.py", "loom-tool", CHECK_RUNTIME_SOURCE),
859
839
  ]
860
840
  if uses_attach_only_path(adoption_path):
861
841
  artifacts.extend(
@@ -1362,6 +1342,34 @@ def copy_file(source: Path, target: Path, force: bool) -> bool:
1362
1342
  return write_text(target, content, force=force)
1363
1343
 
1364
1344
 
1345
+ def sha256_file(path: Path) -> str:
1346
+ digest = hashlib.sha256()
1347
+ with path.open("rb") as handle:
1348
+ for chunk in iter(lambda: handle.read(1024 * 1024), b""):
1349
+ digest.update(chunk)
1350
+ return digest.hexdigest()
1351
+
1352
+
1353
+ def runtime_artifact(path: str, kind: str, source: str) -> dict[str, str]:
1354
+ runtime_sources = {
1355
+ ".loom/bin/loom_init.py": Path(__file__),
1356
+ ".loom/bin/fact_chain_support.py": Path(__file__).with_name("fact_chain_support.py"),
1357
+ ".loom/bin/governance_surface.py": Path(__file__).with_name("governance_surface.py"),
1358
+ ".loom/bin/loom_flow.py": Path(__file__).with_name("loom_flow.py"),
1359
+ ".loom/bin/loom_status.py": Path(__file__).with_name("loom_status.py"),
1360
+ ".loom/bin/runtime_paths.py": Path(__file__).with_name("runtime_paths.py"),
1361
+ ".loom/bin/runtime_state.py": Path(__file__).with_name("runtime_state.py"),
1362
+ ".loom/bin/loom_check.py": Path(__file__).with_name("loom_check.py"),
1363
+ }
1364
+ source_path = runtime_sources[path]
1365
+ return {
1366
+ "path": path,
1367
+ "kind": kind,
1368
+ "source": source,
1369
+ "sha256": sha256_file(source_path),
1370
+ }
1371
+
1372
+
1365
1373
  def manifest_payload(result: dict[str, object]) -> dict[str, object]:
1366
1374
  return {
1367
1375
  "schema_version": "loom-bootstrap-manifest/v1",
@@ -1619,24 +1627,23 @@ def verify_target(target_root: Path, output_path: Path) -> list[str]:
1619
1627
  ):
1620
1628
  if field not in runtime_evidence_report:
1621
1629
  errors.append(f"fact-chain: runtime_evidence is missing `{field}`")
1622
- matching_work_item = None
1623
- for work_item in validated_work_items:
1624
- if work_item.get("id") == current_item_id:
1625
- matching_work_item = work_item
1626
- break
1627
- if matching_work_item is None:
1628
- errors.append(f"init-result is missing the current work item `{current_item_id}`")
1629
- else:
1630
+ bootstrap_work_item = next(
1631
+ (work_item for work_item in validated_work_items if work_item.get("id") == WORK_ITEM_ID),
1632
+ None,
1633
+ )
1634
+ if bootstrap_work_item is None:
1635
+ errors.append(f"init-result is missing the bootstrap work item `{WORK_ITEM_ID}`")
1636
+ elif current_item_id == WORK_ITEM_ID:
1630
1637
  expected_init_fields = {
1631
1638
  "recovery_entry": fact_chain_report["fact_chain"]["entry_points"]["recovery_entry"],
1632
1639
  "validation_entry": fact_chain_report["facts"]["validation_entry"]["value"],
1633
1640
  "workspace_entry": fact_chain_report["facts"]["workspace_entry"]["value"],
1634
1641
  }
1635
1642
  for field, expected_value in expected_init_fields.items():
1636
- actual_value = matching_work_item.get(field)
1643
+ actual_value = bootstrap_work_item.get(field)
1637
1644
  if actual_value != expected_value:
1638
1645
  errors.append(
1639
- f"init-result work item `{current_item_id}` has inconsistent `{field}`: "
1646
+ f"init-result bootstrap work item `{WORK_ITEM_ID}` has inconsistent `{field}`: "
1640
1647
  f"expected `{expected_value}`, got `{actual_value}`"
1641
1648
  )
1642
1649
 
@@ -4,6 +4,7 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import json
7
+ import hashlib
7
8
  import os
8
9
  from pathlib import Path
9
10
  from typing import Any
@@ -85,6 +86,14 @@ def detect_carrier(caller_file: str) -> str | None:
85
86
  return None
86
87
 
87
88
 
89
+ def sha256_file(path: Path) -> str:
90
+ digest = hashlib.sha256()
91
+ with path.open("rb") as handle:
92
+ for chunk in iter(lambda: handle.read(1024 * 1024), b""):
93
+ digest.update(chunk)
94
+ return digest.hexdigest()
95
+
96
+
88
97
  def _default_scene_for_carrier(carrier: str) -> str:
89
98
  if carrier == "repo-local-wrapper":
90
99
  return "repo-local-demo"
@@ -284,6 +293,14 @@ def _validate_bootstrapped_runtime(caller_file: str) -> tuple[dict[str, Any], li
284
293
  runtime_file = runtime_root / Path(relative).name
285
294
  if not runtime_file.exists():
286
295
  errors.append(f"bootstrapped runtime file is missing: `{relative}`")
296
+ continue
297
+ expected_hash = artifact.get("sha256")
298
+ if not isinstance(expected_hash, str) or not expected_hash.strip():
299
+ errors.append(f"bootstrap runtime artifact `{relative}` must declare sha256 provenance")
300
+ continue
301
+ actual_hash = sha256_file(runtime_file)
302
+ if actual_hash != expected_hash:
303
+ errors.append(f"bootstrap runtime artifact `{relative}` sha256 drifted")
287
304
 
288
305
  status = "pass" if not errors else "block"
289
306
  summary = (