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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +25 -15
- package/agents/ai-reviewer.md.tmpl +14 -1
- package/ai/agents/implementer.md +6 -0
- package/ai/agents/reviewer.md +8 -1
- package/bin/ansi.js +12 -0
- package/bin/menu.js +71 -12
- package/bin/riskrails.js +240 -14
- package/bin/uninstall.js +115 -0
- package/bin/wizard.js +72 -0
- package/hooks/AGENTS.md +0 -6
- package/hooks/CLAUDE.md +0 -6
- package/hooks/context-guard.py +11 -1
- package/hooks/dialog-gate.py +3 -2
- package/hooks/guard/decision.py +4 -3
- package/hooks/guard/dialog.py +12 -2
- package/hooks/guard/ere.py +29 -10
- package/hooks/guard/git.py +2 -1
- package/hooks/guard/paths.py +48 -1406
- package/hooks/guard/paths_base.py +66 -0
- package/hooks/guard/paths_bash.py +176 -0
- package/hooks/guard/paths_classify.py +205 -0
- package/hooks/guard/paths_fs.py +137 -0
- package/hooks/guard/paths_human.py +105 -0
- package/hooks/guard/paths_interp.py +162 -0
- package/hooks/guard/paths_movers.py +393 -0
- package/hooks/guard/paths_shell.py +288 -0
- package/hooks/runtime-gate.py +87 -0
- package/hooks/update_notice.py +23 -8
- package/package.json +1 -1
- package/skills/AGENTS.md +0 -6
- package/skills/CLAUDE.md +0 -6
- package/skills/ai-init/templates/.ai/policies/coding.md +9 -0
- package/skills/ai-init/templates/gitignore.snippet +2 -0
- package/skills/ai-task/memory_cleanup.py +213 -0
- package/skills/ai-task/memory_compact.py +25 -0
- package/skills/ai-task/memory_config.py +120 -0
- package/skills/ai-task/memory_export.py +246 -0
- package/skills/ai-task/memory_format.py +7 -3
- package/skills/ai-task/memory_hook.py +172 -0
- package/skills/ai-task/memory_io.py +122 -0
- package/skills/ai-task/memory_migrate.py +187 -0
- package/skills/ai-task/memory_packages.py +83 -0
- package/skills/ai-task/memory_risks.py +84 -0
- package/skills/ai-task/memory_status.py +76 -0
- package/skills/ai-task/memory_sync.py +20 -1481
- package/skills/ai-task/memory_verify.py +316 -0
- package/skills/ai-task/rr_state/cli.py +1 -0
- package/skills/ai-task/rr_state/close.py +2 -2
- package/skills/ai-task/rr_state/dialog.py +32 -7
- package/skills/ai-task/rr_state/dialog_cmd.py +38 -5
- package/skills/ai-task/rr_state/gate.py +10 -4
- package/skills/ai-task/rr_state/labels.py +33 -4
- package/skills/ai-task/rr_state/memory_cmd.py +84 -64
- package/skills/ai-task/rr_state/questions_cmd.py +5 -4
- package/skills/ai-task/rr_state/report.py +73 -10
- package/skills/ai-task/rr_state/report_cmd.py +2 -0
- package/skills/ai-task/rr_state/review.py +18 -14
- package/skills/ai-task/rr_state/start.py +12 -9
- package/skills/ai-task/rr_state/steps.py +16 -7
- package/skills/ai-task/rr_state/verify.py +17 -12
- package/skills/project-update/history/blobs/dac90781793b8a1c8e5f3e0307665b6394d922140c3831c5508d019f79e1ed0a +41 -0
- package/skills/project-update/history/blobs/fa0cb370b024e1a30e1355912032657b08f609e47773a603c193b1e609b0f997 +8 -0
- package/skills/project-update/history/index.json +8 -4
- package/skills/project-update/rr_update/__init__.py +1 -0
- package/skills/project-update/rr_update/apply.py +188 -0
- package/skills/project-update/rr_update/blocks.py +38 -0
- package/skills/project-update/rr_update/build.py +96 -0
- package/skills/project-update/rr_update/cleanup.py +194 -0
- package/skills/project-update/rr_update/cli.py +102 -0
- package/skills/project-update/rr_update/files.py +106 -0
- package/skills/project-update/rr_update/gate.py +60 -0
- package/skills/project-update/rr_update/hints.py +128 -0
- package/skills/project-update/rr_update/history.py +117 -0
- package/skills/project-update/rr_update/kept.py +120 -0
- package/skills/project-update/rr_update/paths.py +108 -0
- package/skills/project-update/rr_update/plan.py +123 -0
- package/skills/project-update/rr_update/report.py +51 -0
- package/skills/project-update/rr_update/rules.py +178 -0
- package/skills/project-update/rr_update/shared.py +74 -0
- package/skills/project-update/rr_update/siblings.py +37 -0
- package/skills/project-update/rr_update/weights.py +171 -0
- package/skills/project-update/update.py +8 -1682
- package/skills/rr-build/SKILL.md +5 -2
- package/skills/rr-setup/SKILL.md +4 -2
- package/skills/rr-setup/setup.py +13 -12
- package/skills/rr-ship/SKILL.md +2 -2
- package/skills/rr-spec/SKILL.md +6 -0
- package/skills/rr-status/SKILL.md +2 -0
- package/skills/rr-status/status.py +5 -3
package/skills/rr-build/SKILL.md
CHANGED
|
@@ -157,10 +157,13 @@ The batch is `[{"question": "…", "options": [{"key": "A", "text": "…"}, …]
|
|
|
157
157
|
`"A: text"` becomes `{"key": "A", "text": "text"}`.
|
|
158
158
|
|
|
159
159
|
Option keys are single letters, A first, at least two; `--recommend` marks the
|
|
160
|
-
one you would pick.
|
|
160
|
+
one you would pick. If `ask` printed `DIALOG_PENDING`, send that dialog. With no
|
|
161
|
+
decision pending (a free question-tool call is denied while one is), put the
|
|
162
|
+
question through the question tool and record the pick with
|
|
163
|
+
`$STATE answer Q1=B --via picker`. Otherwise **stop** and show the questions: while one is pending,
|
|
161
164
|
`step-done` and `close` exit 4. The human answers in the conversation — record
|
|
162
165
|
it with `$STATE answer Q1=B Q2=X:"free text"` or `--prose "1B 2A"` — or fills the
|
|
163
|
-
`[Answer]:` line in `.ai/reports/<task-id>/task.md` §Questions
|
|
166
|
+
`[Answer]:` line in `.ai/reports/<task-id>/task.md` §Questions; that file stays the
|
|
164
167
|
record. Never edit that file, and never answer on the human's behalf.
|
|
165
168
|
|
|
166
169
|
## 6. Hand over by mode
|
package/skills/rr-setup/SKILL.md
CHANGED
|
@@ -164,7 +164,9 @@ formatting fix. Problems you find are written down, never fixed. Never read
|
|
|
164
164
|
line as printed (the `enabledPlugins` line is the human's to add — never
|
|
165
165
|
write it), and the suggested first task:
|
|
166
166
|
`/rr-plan <it>`. Claim nothing was validated that was not run. Suggest
|
|
167
|
-
`git add .ai .gitignore docs/sdlc` plus the instruction files created
|
|
167
|
+
`git add .ai .gitignore docs/sdlc` plus the instruction files created
|
|
168
|
+
(`.ai/memory/` and `.ai/reports/` are git-ignored; memory stays local unless the human runs
|
|
169
|
+
`memory enable --share git`).
|
|
168
170
|
|
|
169
171
|
## --options
|
|
170
172
|
|
|
@@ -243,7 +245,7 @@ riskrails is installed: until then the project's old shapes are not read.
|
|
|
243
245
|
second machine runs the same before its next pull, else a modify/delete
|
|
244
246
|
conflict); never run it yourself.
|
|
245
247
|
7. `$UPDATE --check` and `git diff --stat`; say what changed, what you merged
|
|
246
|
-
and what is the human's. Suggest `git add -A .ai docs/sdlc .gitignore` plus
|
|
248
|
+
and what is the human's. Suggest `git add -A .ai docs/sdlc .gitignore` (the record and task logs are git-ignored) plus
|
|
247
249
|
the runtime directories and instruction files.
|
|
248
250
|
|
|
249
251
|
## --audit
|
package/skills/rr-setup/setup.py
CHANGED
|
@@ -440,7 +440,7 @@ def write(path, text):
|
|
|
440
440
|
|
|
441
441
|
def sibling(directory, name):
|
|
442
442
|
"""A module of this skill or of another, imported once its directory leads sys.path: `python3 -I` puts none
|
|
443
|
-
there, and the module's own imports are by name (
|
|
443
|
+
there, and the module's own imports are by name (memory_export reaches memory_compact that way). Skills are
|
|
444
444
|
installed independently, so a missing module is an ImportError for the caller to answer."""
|
|
445
445
|
if directory not in sys.path:
|
|
446
446
|
sys.path.insert(0, directory)
|
|
@@ -477,7 +477,7 @@ def dialog_on(root):
|
|
|
477
477
|
|
|
478
478
|
|
|
479
479
|
def author_source(cfg):
|
|
480
|
-
"""Where `cfg.author` comes from, in the order
|
|
480
|
+
"""Where `cfg.author` comes from, in the order memory_config.MemoryConfig.author tries them."""
|
|
481
481
|
if cfg.local.get("author"):
|
|
482
482
|
return "local config"
|
|
483
483
|
return next(("$" + name for name in ("USER", "USERNAME") if os.environ.get(name)), "default")
|
|
@@ -494,22 +494,23 @@ def fts5():
|
|
|
494
494
|
|
|
495
495
|
def memory_option(root, git):
|
|
496
496
|
"""Packages-mode project memory: set once memory.json exists, its mode being `current`. `author` is what
|
|
497
|
-
`memory enable` writes without --author (the local config, else $USER):
|
|
497
|
+
`memory enable` writes without --author (the local config, else $USER): memory_config's own answer, never git's."""
|
|
498
498
|
def unavailable(why):
|
|
499
499
|
return {"key": "memory", "state": "unavailable", "why": why}
|
|
500
500
|
if not git:
|
|
501
501
|
return unavailable("not a git work tree")
|
|
502
502
|
try:
|
|
503
|
-
|
|
503
|
+
memory_config = sibling(AI_TASK, "memory_config")
|
|
504
|
+
memory_io = sibling(AI_TASK, "memory_io")
|
|
504
505
|
except ImportError as exc:
|
|
505
506
|
return unavailable("the memory modules are not installed beside state.py (%s)" % exc)
|
|
506
507
|
try:
|
|
507
|
-
cfg =
|
|
508
|
-
except
|
|
508
|
+
cfg = memory_config.load_config(root)
|
|
509
|
+
except memory_io.MemoryError_ as exc:
|
|
509
510
|
return unavailable(str(exc))
|
|
510
511
|
return {"key": "memory", "state": "set" if cfg.present else "unset", "current": cfg.mode if cfg.present else None,
|
|
511
512
|
"author": cfg.author, "author_from": author_source(cfg),
|
|
512
|
-
"period": None if cfg.present else
|
|
513
|
+
"period": None if cfg.present else memory_config.DEFAULTS["period"], "fts5": fts5()}
|
|
513
514
|
|
|
514
515
|
|
|
515
516
|
def runtime_option(root):
|
|
@@ -602,17 +603,17 @@ def memory_decision(option, root, name):
|
|
|
602
603
|
if option["state"] == "set":
|
|
603
604
|
first = choice_option("Keep — %s mode" % option["current"], "keep")
|
|
604
605
|
question = ("Project memory for %s is in %s mode: off keeps closed tasks only in .ai/reports/. packages also writes "
|
|
605
|
-
"one compact
|
|
606
|
-
"%s. Keep it, or run memory enable?" % (name, option["current"], who))
|
|
606
|
+
"one compact file per developer per period under .ai/memory/; both stay local (git-ignored) unless you "
|
|
607
|
+
"run 'state.py memory enable --share git' in your own terminal. %s. Keep it, or run memory enable?" % (name, option["current"], who))
|
|
607
608
|
else:
|
|
608
609
|
first = choice_option("Off — keep files mode", "off")
|
|
609
610
|
question = ("Project memory for %s: off keeps closed tasks only in .ai/reports/. packages also writes one compact "
|
|
610
|
-
"
|
|
611
|
-
"Turn it on?" % (name, option["period"], who, option["period"]))
|
|
611
|
+
"file per developer per %s under .ai/memory/; both stay local (git-ignored) unless you run "
|
|
612
|
+
"'state.py memory enable --share git' in your own terminal. %s, period %s. Turn it on?" % (name, option["period"], who, option["period"]))
|
|
612
613
|
return decision("memory", question, [
|
|
613
614
|
first,
|
|
614
615
|
command_option(state_label(root, "memory", "enable", *period),
|
|
615
|
-
"packages;
|
|
616
|
+
"packages; local, git-ignored record under .ai/memory/"),
|
|
616
617
|
command_option(state_label(root, "memory", "enable", *period, "--index", "sqlite"),
|
|
617
618
|
"plus a local, git-ignored SQLite index; FTS5 %s — without it search scans: same results, slower"
|
|
618
619
|
% ("yes" if option["fts5"] else "no"))])
|
package/skills/rr-ship/SKILL.md
CHANGED
|
@@ -51,8 +51,8 @@ approve in your own terminal, then run close again:
|
|
|
51
51
|
python3 /home/…/skills/ai-task/state.py --root /path/to/project approve --by "<name>"
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
Show the human the summary (§3), the
|
|
55
|
-
command **verbatim** — paths absolute and quoted, because they paste it into
|
|
54
|
+
Show the human the summary (§3), the review's `READ FIRST` lines, the open
|
|
55
|
+
findings, the rollback, and that command **verbatim** — paths absolute and quoted, because they paste it into
|
|
56
56
|
their own shell, where `$AI_HOME` is not set. Then **stop**.
|
|
57
57
|
|
|
58
58
|
- **You approve only through the dialog.** With `.ai/policies/dialog.json`
|
package/skills/rr-spec/SKILL.md
CHANGED
|
@@ -39,6 +39,12 @@ $STATE ask --topic <slug> "<one line>" --option "A: <text>" --option "B: <text>"
|
|
|
39
39
|
$STATE answer --topic <slug> Q1=B # or --prose "1B", or Q1=X:"free text"
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
If `ask` printed `DIALOG_PENDING`, send that dialog. With no decision pending (a
|
|
43
|
+
free question-tool call is denied while one is), put the question through the
|
|
44
|
+
question tool and relay the pick with `$STATE answer --topic <slug> Q1=B --via
|
|
45
|
+
picker`; the questions file stays the record, and the human may still answer in
|
|
46
|
+
the chat or fill `[Answer]:`.
|
|
47
|
+
|
|
42
48
|
If `superpowers:brainstorming` is available, let it drive the conversation; the
|
|
43
49
|
questions and answers still go through `ask` and `answer`. Otherwise:
|
|
44
50
|
|
|
@@ -16,6 +16,8 @@ done
|
|
|
16
16
|
python3 -I "$AI_HOME/skills/rr-status/status.py" --root "$PWD"
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
With a task in flight or a decision open, the first line says who it waits on (`waiting on you` or `waiting on the agent`).
|
|
20
|
+
|
|
19
21
|
After the output, at most one line, and only when a line asks for it:
|
|
20
22
|
|
|
21
23
|
- `root:` is an ancestor of this repository, or `$HOME`: that `.ai/` arms the
|
|
@@ -174,9 +174,11 @@ def main(argv=None):
|
|
|
174
174
|
return 1
|
|
175
175
|
lines, task_id = None, None
|
|
176
176
|
state = read_json(state_file(root))
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
#
|
|
177
|
+
decisions = read_json(os.path.join(root, ".ai", "state", "decision.json")).get("open")
|
|
178
|
+
if state.get("schema") == 7 or (not state.get("task_id") and decisions):
|
|
179
|
+
# A schema-7 task, or an open decision with no task, is state.py's to describe
|
|
180
|
+
# (its first line says who waits); this file's own read stays for an older
|
|
181
|
+
# task, and for an install whose state.py cannot answer.
|
|
180
182
|
done = subprocess.run([sys.executable, "-I", os.path.join(SKILLS, "ai-task", "state.py"),
|
|
181
183
|
"--root", root, "status"], capture_output=True, text=True, check=False)
|
|
182
184
|
if done.returncode == 0 and done.stdout.strip():
|