riskrails 4.1.0 → 4.3.0

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 (92) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/README.md +25 -15
  5. package/agents/ai-reviewer.md.tmpl +14 -1
  6. package/ai/agents/implementer.md +6 -0
  7. package/ai/agents/reviewer.md +8 -1
  8. package/bin/ansi.js +12 -0
  9. package/bin/menu.js +71 -12
  10. package/bin/riskrails.js +240 -14
  11. package/bin/uninstall.js +115 -0
  12. package/bin/wizard.js +72 -0
  13. package/hooks/AGENTS.md +0 -6
  14. package/hooks/CLAUDE.md +0 -6
  15. package/hooks/context-guard.py +11 -1
  16. package/hooks/dialog-gate.py +3 -2
  17. package/hooks/guard/decision.py +4 -3
  18. package/hooks/guard/dialog.py +12 -2
  19. package/hooks/guard/ere.py +29 -10
  20. package/hooks/guard/git.py +2 -1
  21. package/hooks/guard/paths.py +48 -1406
  22. package/hooks/guard/paths_base.py +66 -0
  23. package/hooks/guard/paths_bash.py +176 -0
  24. package/hooks/guard/paths_classify.py +205 -0
  25. package/hooks/guard/paths_fs.py +137 -0
  26. package/hooks/guard/paths_human.py +105 -0
  27. package/hooks/guard/paths_interp.py +162 -0
  28. package/hooks/guard/paths_movers.py +393 -0
  29. package/hooks/guard/paths_shell.py +288 -0
  30. package/hooks/runtime-gate.py +87 -0
  31. package/hooks/update_notice.py +23 -8
  32. package/package.json +1 -1
  33. package/skills/AGENTS.md +0 -6
  34. package/skills/CLAUDE.md +0 -6
  35. package/skills/ai-init/templates/.ai/policies/coding.md +9 -0
  36. package/skills/ai-init/templates/gitignore.snippet +2 -0
  37. package/skills/ai-task/memory_cleanup.py +213 -0
  38. package/skills/ai-task/memory_compact.py +25 -0
  39. package/skills/ai-task/memory_config.py +120 -0
  40. package/skills/ai-task/memory_export.py +246 -0
  41. package/skills/ai-task/memory_format.py +7 -3
  42. package/skills/ai-task/memory_hook.py +172 -0
  43. package/skills/ai-task/memory_io.py +122 -0
  44. package/skills/ai-task/memory_migrate.py +187 -0
  45. package/skills/ai-task/memory_packages.py +83 -0
  46. package/skills/ai-task/memory_risks.py +84 -0
  47. package/skills/ai-task/memory_status.py +76 -0
  48. package/skills/ai-task/memory_sync.py +20 -1481
  49. package/skills/ai-task/memory_verify.py +316 -0
  50. package/skills/ai-task/rr_state/cli.py +1 -0
  51. package/skills/ai-task/rr_state/close.py +2 -2
  52. package/skills/ai-task/rr_state/dialog.py +32 -7
  53. package/skills/ai-task/rr_state/dialog_cmd.py +38 -5
  54. package/skills/ai-task/rr_state/gate.py +10 -4
  55. package/skills/ai-task/rr_state/labels.py +33 -4
  56. package/skills/ai-task/rr_state/memory_cmd.py +84 -64
  57. package/skills/ai-task/rr_state/questions_cmd.py +5 -4
  58. package/skills/ai-task/rr_state/report.py +73 -10
  59. package/skills/ai-task/rr_state/report_cmd.py +2 -0
  60. package/skills/ai-task/rr_state/review.py +18 -14
  61. package/skills/ai-task/rr_state/start.py +12 -9
  62. package/skills/ai-task/rr_state/steps.py +16 -7
  63. package/skills/ai-task/rr_state/verify.py +17 -12
  64. package/skills/project-update/history/blobs/dac90781793b8a1c8e5f3e0307665b6394d922140c3831c5508d019f79e1ed0a +41 -0
  65. package/skills/project-update/history/blobs/fa0cb370b024e1a30e1355912032657b08f609e47773a603c193b1e609b0f997 +8 -0
  66. package/skills/project-update/history/index.json +8 -4
  67. package/skills/project-update/rr_update/__init__.py +1 -0
  68. package/skills/project-update/rr_update/apply.py +188 -0
  69. package/skills/project-update/rr_update/blocks.py +38 -0
  70. package/skills/project-update/rr_update/build.py +96 -0
  71. package/skills/project-update/rr_update/cleanup.py +194 -0
  72. package/skills/project-update/rr_update/cli.py +102 -0
  73. package/skills/project-update/rr_update/files.py +106 -0
  74. package/skills/project-update/rr_update/gate.py +60 -0
  75. package/skills/project-update/rr_update/hints.py +128 -0
  76. package/skills/project-update/rr_update/history.py +117 -0
  77. package/skills/project-update/rr_update/kept.py +120 -0
  78. package/skills/project-update/rr_update/paths.py +108 -0
  79. package/skills/project-update/rr_update/plan.py +123 -0
  80. package/skills/project-update/rr_update/report.py +51 -0
  81. package/skills/project-update/rr_update/rules.py +178 -0
  82. package/skills/project-update/rr_update/shared.py +74 -0
  83. package/skills/project-update/rr_update/siblings.py +37 -0
  84. package/skills/project-update/rr_update/weights.py +171 -0
  85. package/skills/project-update/update.py +8 -1682
  86. package/skills/rr-build/SKILL.md +5 -2
  87. package/skills/rr-setup/SKILL.md +4 -2
  88. package/skills/rr-setup/setup.py +13 -12
  89. package/skills/rr-ship/SKILL.md +2 -2
  90. package/skills/rr-spec/SKILL.md +6 -0
  91. package/skills/rr-status/SKILL.md +2 -0
  92. package/skills/rr-status/status.py +5 -3
@@ -0,0 +1,76 @@
1
+ """Status and show: the lines `state.py memory status` prints and the rendering of one task's record."""
2
+ import os
3
+
4
+ import memory_compact as mc
5
+ import memory_config as mcfg
6
+ import memory_export as mexp
7
+ import memory_format as mf
8
+ import memory_hook as mhook
9
+ import memory_io as mio
10
+ import memory_packages as mpkg
11
+
12
+
13
+ def status_lines(root):
14
+ cfg = mcfg.load_config(root)
15
+ packages = mpkg.load_packages(root)
16
+ size = sum(os.path.getsize(os.path.join(mio.memory_dir(root), n)) for n in packages)
17
+ books = mpkg.read_batches(root)
18
+ branch = mio.current_branch(root)
19
+ pending = mexp.pending_ids(root, cfg) if cfg.packages else []
20
+ legacy = unmigrated(root, packages)
21
+ lines = ["mode: %s%s" % (cfg.mode, "" if cfg.present else " (no %s)" % mio.POLICY_REL),
22
+ "period: %s · author: %s · index: %s%s" % (cfg.period, cfg.author, cfg.index, fts_line(cfg)),
23
+ "open batch: %s" % (books["open"].get(branch) or "none") + " (branch %s)" % branch,
24
+ "packages: %d · %s bytes" % (len(packages), mf.fmt_n(size)),
25
+ "closed, not exported: %s" % (", ".join(pending) if pending else "none"),
26
+ "legacy, not migrated: %d%s" % (len(legacy), " — state.py memory migrate --report" if legacy else ""),
27
+ "pre-push: %s" % ("not needed — the record is local (.ai/memory/ is git-ignored)"
28
+ if not mio.shared(root) else mhook.hook_state(root)), "cleanup: %s" % ("on" if cfg.cleanup else "off")]
29
+ return lines
30
+
31
+
32
+ def fts_line(cfg):
33
+ if cfg.index != "sqlite":
34
+ return ""
35
+ import memory_store # pylint: disable=import-outside-toplevel
36
+ if memory_store.fts5_available():
37
+ return " · fts5: yes"
38
+ import sqlite3 # pylint: disable=import-outside-toplevel
39
+ return " · FTS5 unavailable in this SQLite %s: search scans; results identical, slower" % sqlite3.sqlite_version
40
+
41
+
42
+ def unmigrated(root, packages):
43
+ sealed = mpkg.sealed_task_ids(packages)
44
+ reports = os.path.join(root, ".ai", "reports")
45
+ out = []
46
+ for name in sorted(os.listdir(reports)) if os.path.isdir(reports) else []:
47
+ path = os.path.join(reports, name, "events.jsonl")
48
+ if mf.LEGACY_ID_RE.match(name) and name not in sealed and b'"task_closed"' in (mio.read_bytes(path) or b""):
49
+ out.append(name)
50
+ return out
51
+
52
+
53
+ def show(root, task_id, fmt="md", rid=None):
54
+ import memory_store # pylint: disable=import-outside-toplevel
55
+ cfg = mcfg.load_config(root)
56
+ history = memory_store.open_history(root, cfg)
57
+ if rid:
58
+ found = [e for e in history.all_entries() if e.get("rid") == rid]
59
+ if not found:
60
+ raise mio.MemoryError_("no entry %s" % rid, 1)
61
+ return [mf.canonical(found[0]).decode("utf-8")]
62
+ if task_id == memory_store.current_task(root):
63
+ found = mc.compact_instances(mc.FsReader(root), task_id, "tracked", cfg.excerpt_max_bytes)
64
+ entries = [e for c in found for e in c.entries]
65
+ lines = ["# %s — in flight — live state ('state.py status' is the authority)" % task_id, ""]
66
+ return lines + mf.render_task_md(entries)[1:] if fmt == "md" else \
67
+ [mf.canonical(e).decode("utf-8") for e in entries]
68
+ entries = history.entries(task_id)
69
+ if not entries:
70
+ raise mio.MemoryError_("nothing recorded for %s" % task_id, 1)
71
+ if fmt == "json":
72
+ return [mf.canonical(e).decode("utf-8") for e in entries]
73
+ out = []
74
+ for inst in sorted({e.get("inst") for e in entries}):
75
+ out += mf.render_task_md([e for e in entries if e.get("inst") == inst])
76
+ return out