@rafinery/cli 0.13.0 → 0.15.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/CHANGELOG.md +41 -0
- package/bin/rafa.mjs +4 -15
- package/blueprint/.claude/agents/atlas.md +27 -5
- package/blueprint/.claude/agents/bloom.md +24 -4
- package/blueprint/.claude/agents/prism.md +12 -3
- package/blueprint/.claude/agents/sage.md +7 -5
- package/blueprint/.claude/commands/rafa.md +19 -8
- package/blueprint/.claude/rafa/contract.md +116 -2
- package/blueprint/.claude/skills/rafa-build/SKILL.md +5 -6
- package/blueprint/.claude/skills/rafa-improve/SKILL.md +18 -3
- package/blueprint/.claude/skills/rafa-plan/SKILL.md +17 -17
- package/blueprint/.claude/skills/rafa-sage/SKILL.md +11 -7
- package/blueprint/.claude/skills/rafa-scan/SKILL.md +44 -10
- package/blueprint/.claude/skills/rafa-security/SKILL.md +15 -8
- package/lib/blueprint.mjs +0 -1
- package/lib/doctor.mjs +1 -1
- package/lib/gate/compile.mjs +10 -3
- package/lib/gate/verify-citations.mjs +8 -1
- package/lib/migrations/index.mjs +49 -2
- package/lib/releases.mjs +45 -0
- package/package.json +1 -1
- package/skills-bundle/skills-manifest.json +1 -1
- package/blueprint/.claude/skills/rafa-distill/SKILL.md +0 -126
- package/lib/ci-setup.mjs +0 -172
- package/lib/distill.mjs +0 -665
- package/lib/distiller/schema-ladder.mjs +0 -186
package/lib/ci-setup.mjs
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
// rafa ci-setup — install the reconciliation workflow (working-set
|
|
2
|
-
// architecture, ratified 2026-07-10, rules 6–7): the org's own CI folds
|
|
3
|
-
// branch→branch merges mechanically and DISTILLS merge-to-main with the org's
|
|
4
|
-
// own LLM key. Writes .github/workflows/rafa-reconcile.yml and names the
|
|
5
|
-
// secrets to configure — it configures nothing itself (secrets are the org's;
|
|
6
|
-
// nothing sensitive ever transits rafinery).
|
|
7
|
-
|
|
8
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
9
|
-
import { dirname, join } from "node:path";
|
|
10
|
-
|
|
11
|
-
const WORKFLOW_PATH = ".github/workflows/rafa-reconcile.yml";
|
|
12
|
-
|
|
13
|
-
const WORKFLOW = `# rafa reconcile — knowledge propagates exactly like the code it describes.
|
|
14
|
-
#
|
|
15
|
-
# branch → parent branch merge = MECHANICAL FOLD (no LLM, no prism)
|
|
16
|
-
# branch → default branch merge = DISTILLATION (prism-validated vs merged main,
|
|
17
|
-
# compile-gated, pushed to the brain repo)
|
|
18
|
-
#
|
|
19
|
-
# Secrets (Settings → Secrets and variables → Actions):
|
|
20
|
-
# RAFA_MCP_KEY an agent key for this repo (platform → repo → Agent access)
|
|
21
|
-
# ANTHROPIC_API_KEY the ORG'S OWN LLM key — used only inside this CI for
|
|
22
|
-
# distillation; never stored on the rafinery platform
|
|
23
|
-
# RAFA_BRAIN_TOKEN a token with push access to the BRAIN repo (distill only)
|
|
24
|
-
#
|
|
25
|
-
# Fires on the merge EVENT itself (PR closed+merged), so squash/rebase merges are
|
|
26
|
-
# detected correctly. The distill job ALSO runs an ancestry sweep: any still-active
|
|
27
|
-
# working-set row (any branch) whose capturedAtSha is reachable from merged main is
|
|
28
|
-
# provably-merged backlog — an earlier merge whose distill never ran, or a direct
|
|
29
|
-
# push — and folds into the same run. The sweep needs full history (fetch-depth: 0).
|
|
30
|
-
# If distillation cannot run (missing secret, failed gate) it fails LOUD and the
|
|
31
|
-
# branch's working set stays intact — the next dev session gets the standard
|
|
32
|
-
# distill offer (fallback chain).
|
|
33
|
-
|
|
34
|
-
name: rafa reconcile
|
|
35
|
-
|
|
36
|
-
on:
|
|
37
|
-
pull_request:
|
|
38
|
-
types: [closed]
|
|
39
|
-
|
|
40
|
-
jobs:
|
|
41
|
-
fold:
|
|
42
|
-
name: fold working set (branch → parent)
|
|
43
|
-
if: github.event.pull_request.merged == true && github.event.pull_request.base.ref != github.event.repository.default_branch
|
|
44
|
-
runs-on: ubuntu-latest
|
|
45
|
-
steps:
|
|
46
|
-
- uses: actions/checkout@v4
|
|
47
|
-
- uses: actions/setup-node@v4
|
|
48
|
-
with:
|
|
49
|
-
node-version: 20
|
|
50
|
-
- name: Mechanical fold (no LLM — rigor lives at main)
|
|
51
|
-
env:
|
|
52
|
-
RAFA_MCP_KEY: \${{ secrets.RAFA_MCP_KEY }}
|
|
53
|
-
RAFA_MCP_URL: \${{ secrets.RAFA_MCP_URL }} # deployed platform /api/mcp — localhost never works from CI
|
|
54
|
-
RAFA_HOOKS_DISABLED: "1" # headless — the M5 sensors are session instruments
|
|
55
|
-
run: npx -y @rafinery/cli fold --from "\${{ github.event.pull_request.head.ref }}" --to "\${{ github.event.pull_request.base.ref }}"
|
|
56
|
-
|
|
57
|
-
distill:
|
|
58
|
-
name: distill working set (merge to main)
|
|
59
|
-
if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == github.event.repository.default_branch
|
|
60
|
-
runs-on: ubuntu-latest
|
|
61
|
-
steps:
|
|
62
|
-
- uses: actions/checkout@v4
|
|
63
|
-
with:
|
|
64
|
-
ref: \${{ github.event.repository.default_branch }} # merged main = the validation target
|
|
65
|
-
fetch-depth: 0 # full history — the ancestry sweep proves prior merges
|
|
66
|
-
- uses: actions/setup-node@v4
|
|
67
|
-
with:
|
|
68
|
-
node-version: 20
|
|
69
|
-
# ISOLATED install — never \`npm i\` inside the client checkout: a pnpm
|
|
70
|
-
# workspace repo has "workspace:*" deps npm cannot parse (EUNSUPPORTEDPROTOCOL).
|
|
71
|
-
- name: Install the Agent SDK (isolated dir; runs on the org's own key)
|
|
72
|
-
run: |
|
|
73
|
-
mkdir -p "\$RUNNER_TEMP/rafa-sdk" && cd "\$RUNNER_TEMP/rafa-sdk"
|
|
74
|
-
npm init -y > /dev/null
|
|
75
|
-
npm i @anthropic-ai/claude-agent-sdk
|
|
76
|
-
- name: Distill into the org brain (prism-validated, compile-gated)
|
|
77
|
-
env:
|
|
78
|
-
ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}
|
|
79
|
-
RAFA_MCP_KEY: \${{ secrets.RAFA_MCP_KEY }}
|
|
80
|
-
RAFA_MCP_URL: \${{ secrets.RAFA_MCP_URL }} # deployed platform /api/mcp — localhost never works from CI
|
|
81
|
-
RAFA_BRAIN_TOKEN: \${{ secrets.RAFA_BRAIN_TOKEN }}
|
|
82
|
-
RAFA_AGENT_SDK_DIR: \${{ runner.temp }}/rafa-sdk
|
|
83
|
-
RAFA_HOOKS_DISABLED: "1" # headless — the M5 sensors are session instruments
|
|
84
|
-
RAFA_MERGE_SHA: \${{ github.event.pull_request.merge_commit_sha }} # keys the run record
|
|
85
|
-
RAFA_TARGET_BRANCH: \${{ github.event.pull_request.base.ref }}
|
|
86
|
-
run: npx -y @rafinery/cli distill --headless "\${{ github.event.pull_request.head.ref }}"
|
|
87
|
-
`;
|
|
88
|
-
|
|
89
|
-
// Pristine-detection for upgrades: a byte-diff alone cannot tell "user tuned
|
|
90
|
-
// this" from "our template moved on" — and mislabeling a stale pristine
|
|
91
|
-
// install as tuned strands it on old behavior forever (the ancestry sweep is
|
|
92
|
-
// inert without fetch-depth: 0). Comparison ignores comments/blank lines;
|
|
93
|
-
// PREVIOUS_NORMALIZED holds every historical pristine body, so a file that
|
|
94
|
-
// matches one is upgraded in place and only a genuinely tuned file is left
|
|
95
|
-
// alone. (Comment-only tuning is knowingly not preserved.)
|
|
96
|
-
const normalize = (s) =>
|
|
97
|
-
s
|
|
98
|
-
.split("\n")
|
|
99
|
-
.map((l) => l.trimEnd())
|
|
100
|
-
.filter((l) => {
|
|
101
|
-
const t = l.trim();
|
|
102
|
-
return t !== "" && !t.startsWith("#");
|
|
103
|
-
})
|
|
104
|
-
.join("\n");
|
|
105
|
-
const PREVIOUS_NORMALIZED = [
|
|
106
|
-
// v1 (pre ancestry-sweep, pre run-record): identical body minus the lines
|
|
107
|
-
// those two features added. Derived, not duplicated — v1 never shipped a
|
|
108
|
-
// byte that differs otherwise.
|
|
109
|
-
normalize(WORKFLOW)
|
|
110
|
-
.split("\n")
|
|
111
|
-
.filter(
|
|
112
|
-
(l) =>
|
|
113
|
-
!l.includes("fetch-depth: 0") &&
|
|
114
|
-
!l.includes("RAFA_MERGE_SHA") &&
|
|
115
|
-
!l.includes("RAFA_TARGET_BRANCH"),
|
|
116
|
-
)
|
|
117
|
-
.join("\n"),
|
|
118
|
-
];
|
|
119
|
-
|
|
120
|
-
export default async function ciSetup(args = []) {
|
|
121
|
-
const ROOT = process.cwd();
|
|
122
|
-
const target = join(ROOT, WORKFLOW_PATH);
|
|
123
|
-
|
|
124
|
-
console.log(
|
|
125
|
-
"OPTIONAL — the platform reconciles merges automatically (no CI, no repo secrets).\n" +
|
|
126
|
-
"This wires the org-CI ADAPTER instead: reconciliation compute runs in YOUR\n" +
|
|
127
|
-
"GitHub Actions on YOUR secrets. Most teams should skip this.\n",
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
if (existsSync(target)) {
|
|
131
|
-
const current = readFileSync(target, "utf8");
|
|
132
|
-
if (current === WORKFLOW) {
|
|
133
|
-
console.log(`✓ ${WORKFLOW_PATH} is already current`);
|
|
134
|
-
} else if (args.includes("--overwrite")) {
|
|
135
|
-
writeFileSync(target, WORKFLOW);
|
|
136
|
-
console.log(`✓ ${WORKFLOW_PATH} updated (--overwrite)`);
|
|
137
|
-
} else if (PREVIOUS_NORMALIZED.includes(normalize(current))) {
|
|
138
|
-
writeFileSync(target, WORKFLOW);
|
|
139
|
-
console.log(
|
|
140
|
-
`✓ ${WORKFLOW_PATH} upgraded from an older pristine template (no local tuning detected)`,
|
|
141
|
-
);
|
|
142
|
-
} else {
|
|
143
|
-
console.log(
|
|
144
|
-
`! ${WORKFLOW_PATH} exists and differs — left untouched (yours may be tuned).\n` +
|
|
145
|
-
" Re-run with --overwrite to replace it.",
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
} else {
|
|
149
|
-
mkdirSync(dirname(target), { recursive: true });
|
|
150
|
-
writeFileSync(target, WORKFLOW);
|
|
151
|
-
console.log(`✓ wrote ${WORKFLOW_PATH}`);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
console.log(`
|
|
155
|
-
Next steps (repo Settings → Secrets and variables → Actions):
|
|
156
|
-
1. RAFA_MCP_KEY — mint on the platform (repo → Agent access); scope: this repo.
|
|
157
|
-
2. RAFA_MCP_URL — your DEPLOYED platform's MCP endpoint (https://<host>/api/mcp).
|
|
158
|
-
A localhost dev URL can never work from a CI runner.
|
|
159
|
-
3. ANTHROPIC_API_KEY — the ORG'S OWN LLM key. Used only inside YOUR CI for
|
|
160
|
-
merge-to-main distillation; never stored on the rafinery
|
|
161
|
-
platform (hard rule).
|
|
162
|
-
4. RAFA_BRAIN_TOKEN — a token with push access to the BRAIN repo (the distill
|
|
163
|
-
job pushes validated knowledge there).
|
|
164
|
-
5. Commit the workflow via your normal MR flow.
|
|
165
|
-
6. Verify the whole capture chain: npx @rafinery/cli doctor (sensors, scripts,
|
|
166
|
-
platform round-trip — exit 1 names any fix).
|
|
167
|
-
|
|
168
|
-
The rigor gradient this wires: dev↔dev = CAS + session prompt · branch↔branch =
|
|
169
|
-
free mechanical fold · branch→main = full distillation + gates. Cost tracks
|
|
170
|
-
consequence. Without CI, nothing is lost — the next dev session's bootstrap
|
|
171
|
-
digest offers the same reconciliation (/rafa distill).`);
|
|
172
|
-
}
|