@ericrisco/rsc 4.0.4 → 4.0.5

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/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.0.4",
2
+ "version": "4.0.5",
3
3
  "counts": {
4
4
  "skills": 274,
5
5
  "agents": 34,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ericrisco/rsc",
3
- "version": "4.0.4",
3
+ "version": "4.0.5",
4
4
  "description": "A guided harness builder that turns your goal into a minimal, verified AI-agent setup using strict best practices.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -61,7 +61,7 @@ Every spec answers four questions, and `spec:gate` refuses one dated 2026-11-03
61
61
 
62
62
  Tier 2, a contradiction with a recorded decision, a gap that would make the build unsafe, or no convergence in 3 rounds: the task goes to the **decision queue** (`## Decision queue` in `progress/<slug>.md`) with its evidence, and the agent **continues with the independent tasks**. The run never waits at 2 a.m. for an answer.
63
63
 
64
- Every entry carries a kind, one line each:
64
+ Every entry carries a kind, one line each, in exactly this form (no bold, no other bullet):
65
65
 
66
66
  ```markdown
67
67
  - [blocking] Q3 — <what must be decided>, <evidence>, <task>
@@ -102,6 +102,8 @@ Autopilot does not stop the run for questions — it **parks**: real ambiguity,
102
102
  - `implement` parks `blocking` items and continues with the independent tasks.
103
103
  - `ship` lands by the rule below.
104
104
 
105
+ **Never hand the turn back mid-run.** No "¿sigo?" / "shall I continue?": not between phases, not while reviewers run. Background reviewers are waited for (their completion notice, or run them in the foreground); ending the turn to wait ends a headless run. A later "continue" from the person resumes the run; it is **not** approval for a tier-2 merge, which needs an explicit yes to that merge.
106
+
105
107
  **Landing — there is always a legal path.** A remote exists → open a PR; self-merge only when `rsc risk` says tier 0-1, CI is green and no `blocking` entry is open; `review-after` entries go into the PR body. No remote → **park**: leave the branch committed, write the explainer, the open entries and the exact merge command for the human into `progress/<slug>.md`, and stop. Never merge locally around the branch guard: when `rsc main status` says `closed: true`, the guard denies it.
106
108
 
107
109
  Narrate in the `orient` voice: name each stage as it passes and show its artifact, one line each.
@@ -115,7 +115,7 @@ review of the task, this first one included. Round 1 is the task's first review,
115
115
  | --- | --- |
116
116
  | 0 | none — the controls (e) still run |
117
117
  | 1 | one fresh-context reviewer; frozen brief in `references/per-task-review.md` |
118
- | 2 | the three refuters (`refuter-correctness` · `refuter-security` · `refuter-tests`) in parallel, as `../review/SKILL.md` runs them; then `review ledger panel <slug>/<task> --lenses correctness,security,tests` — the push gate checks it |
118
+ | 2 | the three refuters (`refuter-correctness` · `refuter-security` · `refuter-tests`) in parallel, as `../review/SKILL.md` runs them; then `review ledger panel <slug>/<task> --lenses correctness,security,tests` — the push gate checks it. Wait for every reviewer inside the turn; never end the turn to ask whether to continue |
119
119
 
120
120
  Every reviewer gets the **spec**, the **diff as a file** (`scripts/review-package <BASE> <HEAD>`, BASE
121
121
  = the task's *recorded* base sha, never `HEAD~1`), the **surrounding code** at that sha (not just the
package/targets/claude.js CHANGED
@@ -45,6 +45,8 @@ export function hookWiringOf(entry) {
45
45
  // plus the legacy cat-form) from settings.json, across all events. User hooks and
46
46
  // other settings are preserved. Empty event arrays (and an empty hooks object) are
47
47
  // pruned so we don't leave noise behind.
48
+ const ATTRIBUTION_MARKER = '.rsc/attribution-default';
49
+
48
50
  export function unwireHook(paths) {
49
51
  // The bootstrap lives in the COMMITTED tree, so leaving it behind does not just orphan a file the
50
52
  // way a stray `.rsc/` entry would — it leaves an executable in something the user pushes. Nothing
@@ -62,7 +64,18 @@ export function unwireHook(paths) {
62
64
  if (!existsSync(file)) return removed;
63
65
  let settings;
64
66
  try { settings = JSON.parse(readFileSync(file, 'utf8')); } catch { return removed; }
65
- if (!settings.hooks) return removed;
67
+ // wireHook's attribution default goes back out with it — only when wireHook wrote it (the marker)
68
+ // and it is still untouched. The same value set by the person before rsc stays theirs.
69
+ const marker = join(paths.projectRoot, ATTRIBUTION_MARKER);
70
+ const a = settings.attribution;
71
+ const ours = existsSync(marker) && a && Object.keys(a).length === 2 && a.commit === '' && a.pr === '';
72
+ if (ours) delete settings.attribution;
73
+ try { rmSync(marker, { force: true }); } catch { /* cleanup never fails the uninstall */ }
74
+ if (!settings.hooks) {
75
+ if (!ours) return removed;
76
+ writeFileSync(file, JSON.stringify(settings, null, 2) + '\n');
77
+ return [...removed, file];
78
+ }
66
79
  for (const event of Object.keys(settings.hooks)) {
67
80
  settings.hooks[event] = (settings.hooks[event] || []).filter((e) => {
68
81
  const s = hookWiringOf(e);
@@ -319,6 +332,15 @@ export function wireHook(paths, sourceMd, policy = {}) {
319
332
  }
320
333
  if (!settings.hooks.PreToolUse.length) delete settings.hooks.PreToolUse;
321
334
 
335
+ // Authorship is the responsible person, never an AI trailer (constitution P8). Claude Code's own
336
+ // default adds a Co-Authored-By line to commits and a footer to PRs, and the 4.0.4 run had to rebase
337
+ // them out by hand. Empty strings hide both. A choice already in the file is the person's and stays.
338
+ if (settings.attribution === undefined && settings.includeCoAuthoredBy === undefined) {
339
+ settings.attribution = { commit: '', pr: '' };
340
+ mkdirSync(join(paths.projectRoot, '.rsc'), { recursive: true });
341
+ writeFileSync(join(paths.projectRoot, ATTRIBUTION_MARKER), '');
342
+ }
343
+
322
344
  mkdirSync(dirname(file), { recursive: true });
323
345
  writeFileSync(file, JSON.stringify(settings, null, 2) + '\n');
324
346