0xray 4.0.16 → 4.0.17

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.16",
3
+ "version": "4.0.17",
4
4
  "description": "0xRay suit for Grok, Hermes, OpenClaw, OpenCode: mill+inspect, Codex, 7 MCP servers. Costume 45/42 is opt-in foundry, not the default wear.",
5
5
  "author": {
6
6
  "name": "0xRay AI",
@@ -67,13 +67,13 @@ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `g
67
67
  - **Peer test:** another instance with only worn 0xRay continues the ticket. No command stream.
68
68
  - **Wear first:** Read `.xray/state/STATION.md`. Same cloud. Same critic (resume only). Dummy Reads Station.
69
69
  - **Dummy tests `SKILLS.md`:** a suited dummy proves the worn catalog. Same-sess bodies keep context and hold a Station card.
70
- - **Ship track:** always branch + worktree/aside + PR. Docs as you go. Builds. Rollback = close the PR.
70
+ - **Ship track:** always branch + worktree/aside + PR. Docs as you go. Builds. Rollback = close the PR. **Subject review. Fix n ship.** After critic PASS, review dest/domain, close leftovers, then mill-gate D. PASS is not ship. **Groover is not Repertoire.**
71
71
  - **Publish:** stay logged in (do not `npm logout`). Every time run `npm publish --access public` in the live TTY. Paste the clickable `auth/cli` URL. No Enter, no VM browser, no subagent, no 6-digit code in chat. Poll `npm view` until live. Then prove **fresh** and **upgrade** registry installs. `npx 0xray validate` is the wear check (not leftover init.sh). `npm view` is not an install.
72
72
  - **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
73
- - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes.
73
+ - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
74
74
  - **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
75
75
  - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
76
- - **Close:** loop until Station is done. Compact: Station survives the cut. Repertoire keeps names.
76
+ - **Close:** loop until Station is done. Compact: Station survives the cut. Overlay dest names are OP-PROC — reload `repertoire-working.json` `opProcNames`, not Station.
77
77
  - **Board:** critic Strict comments; forge implements; lead stays main thread.
78
78
  - **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
79
79
  - **Ship matrix:** `LEAD-CADENCE.md` Decision matrix — A PR+CI · B pack · C `release:docs-check` · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.16",
3
+ "version": "4.0.17",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",
package/dist/CHANGELOG.md CHANGED
@@ -20,6 +20,11 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
20
20
  - **Publish OTP latch** — stay logged in (do not `npm logout`). Every time run `npm publish --access public` in the live TTY (no `--auth-type=web`, no `--otp=` from chat, no `tee`). Paste the clickable `auth/cli` URL. Do not ask for a 6-digit authenticator code in chat. Do not press Enter. Do not hand publish to a browser subagent. Poll `npm view` until the version is live. Then prove **fresh** and **upgrade** registry installs. `npm view` is not an install.
21
21
  - **`npx 0xray validate` cleansed** — no longer shells leftover `.opencode/init.sh` (macOS `md5` + `enforcer-config.json`). Wear check: `REQUIRED_PACK_PATHS`, Cursor hooks, mill+inspect, repertoire. `init.sh` still boots OpenCode but accepts Linux `md5sum` and consumer `.xray/codex.json`.
22
22
  - **Swamp reflection (new arch)** — `docs/reflections/swamp-new-arch-reflection-2026-09-20.md`. Card, organ, hook. Lying metal. Live tarball lag.
23
+ - **Clean ticks every cycle** — `/loop` prompt is rewritten at the end of every live tick. `subscribe_timer` name-dedupe does not update the prompt. Unsubscribe then resubscribe. A tick that contradicts metal is dirty: rewrite, do not act. Not on Station.
24
+ - **Idle `/loop` stop** — if Station `Working` and the WAVEBOARD (open ship PR, live OTP, unfinished close) are idle, unsubscribe and do not resubscribe. A parked mill is not an active wave.
25
+ - **Subject review. Fix n ship.** After board PASS, review the worn dest / domain (not only CI), close leftovers, then mill-gate D. PASS is not ship. On `LEAD-CADENCE.md` Ship track + `SEATS.md` Reviewer. Not on Station.
26
+ - **OP-PROC reload after compact** — overlay dest names *are* OP-PROC. Heat writes them to `.xray/state/repertoire-working.json` `opProcNames`. Station stays a ticket (count + four working matches). Not a new skill.
27
+ - **Groover is not Repertoire.** Groover was a broken experiment of the organ. Do not grow dest from Groover field as if that is the KB. On `LEAD-CADENCE.md` Heads from tails. Not on Station.
23
28
 
24
29
  ### 🔄 Changes
25
30
  - **Durable Hold npm** — heat + `cursorBootNeedsRefresh` + `npx 0xray validate` drop/fail `Hold npm` on Station. Identity stays. Mill-gate holds the ship latch. Not a new skill.
@@ -29,6 +34,34 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
29
34
 
30
35
  ---
31
36
 
37
+ ## [4.0.17] - 2026-09-22
38
+
39
+ ### 🔄 Changes
40
+
41
+ ### ✨ Features
42
+ - feat: write session-*.json from Cursor heat when HEAD moves (363186a02)
43
+ - feat: persist overlay OP-PROC on repertoire-working after compact heat (8c55793e8)
44
+
45
+ ### 📚 Documentation
46
+ - docs: ASCII gather/store/retrieve trees for Station memory (d8f2f3b89)
47
+ - docs: Station is always the pickup memory after compact (bec431c61)
48
+ - docs: Groover is not Repertoire — do not grow dest from Groover field (203147d19)
49
+ - docs: Subject review. Fix n ship. — dest review then leftover then D (ad4ffa7f6)
50
+ - docs: stop /loop when the card and WAVEBOARD are idle (60f0fd53f)
51
+ - docs: clean ticks every cycle — rewrite /loop prompt, do not act on stale metal (e71a19559)
52
+
53
+ ### 🧪 Tests
54
+ - test: match Compact cut wording on Station-as-memory (7f9a4f091)
55
+
56
+ ### 🔎 Other Changes
57
+ - Merge main — include weekday-mirror #97 in 4.0.17 tarball (86fdec7ce)
58
+ - Merge pull request #97 from 0xRayAI/cursor/weekday-mirror-dist-voice-9b4d (d0853aad1)
59
+ - docs(grok-bot): weekday mirror for Dist reply voice and CoS wake hygiene (f91233b59)
60
+ - Merge branch 'cursor/clean-ticks-fbe0' — clean ticks every cycle (12dd06362)
61
+ - Merge branch 'cursor/leftover-validate-d-fbe0' — release 4.0.16 live, leftover validate gone (8fa037212)
62
+
63
+ ---
64
+
32
65
  ## [4.0.16] - 2026-09-20
33
66
 
34
67
  ### 🔄 Changes
@@ -4,6 +4,7 @@
4
4
  * sessionStart is unavailable on managed cloud; first preToolUse / afterFileEdit boots.
5
5
  */
6
6
 
7
+ import { execFileSync } from 'node:child_process';
7
8
  import fs from 'fs';
8
9
  import path from 'path';
9
10
  import {
@@ -152,12 +153,114 @@ export function cursorBootNeedsRefresh(existing, root) {
152
153
  return false;
153
154
  }
154
155
 
156
+ function sessionCaptureStampPath(root) {
157
+ return path.join(root, '.xray', 'state', 'session-capture-stamp.json');
158
+ }
159
+
160
+ function readSessionCaptureConfig(root) {
161
+ let cfg = {};
162
+ try {
163
+ const raw = JSON.parse(fs.readFileSync(path.join(root, '.xray', 'features.json'), 'utf8'));
164
+ cfg = raw.inference_session_capture || {};
165
+ } catch {
166
+ cfg = {};
167
+ }
168
+ return {
169
+ enabled: cfg.enabled === true,
170
+ minCommits: typeof cfg.min_commits === 'number' && cfg.min_commits > 0 ? cfg.min_commits : 3,
171
+ lookback: typeof cfg.lookback_commits === 'number' && cfg.lookback_commits > 0 ? cfg.lookback_commits : 20,
172
+ };
173
+ }
174
+
175
+ function readSessionCaptureStamp(root) {
176
+ try {
177
+ return JSON.parse(fs.readFileSync(sessionCaptureStampPath(root), 'utf8'));
178
+ } catch {
179
+ return null;
180
+ }
181
+ }
182
+
183
+ function gitCommitSubjects(root, args) {
184
+ try {
185
+ const out = execFileSync('git', ['log', '--format=%h||%s', '--no-merges', ...args], {
186
+ cwd: root,
187
+ encoding: 'utf8',
188
+ timeout: 5000,
189
+ stdio: ['ignore', 'pipe', 'pipe'],
190
+ });
191
+ return String(out)
192
+ .split('\n')
193
+ .map((line) => line.trim())
194
+ .filter(Boolean)
195
+ .map((line) => {
196
+ const idx = line.indexOf('||');
197
+ return {
198
+ hash: idx === -1 ? line : line.slice(0, idx),
199
+ message: idx === -1 ? '' : line.slice(idx + 2),
200
+ };
201
+ });
202
+ } catch {
203
+ return [];
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Cursor never runs the git post-commit hook. When HEAD moves, write the same
209
+ * session-*.json the kernel already knows how to ingest. Dedup per HEAD.
210
+ */
211
+ export function maybeCaptureSessionOnHeadMove(root) {
212
+ const cfg = readSessionCaptureConfig(root);
213
+ if (!cfg.enabled) return null;
214
+ const git = readGitBrief(root);
215
+ if (!git || !git.head) return null;
216
+ const stamp = readSessionCaptureStamp(root);
217
+ if (stamp && stamp.head === git.head) return null;
218
+
219
+ const commits = stamp && stamp.head
220
+ ? gitCommitSubjects(root, [`${stamp.head}..HEAD`])
221
+ : gitCommitSubjects(root, ['-n', String(cfg.lookback)]);
222
+ if (commits.length < cfg.minCommits) return null;
223
+
224
+ const sessionId = `session-${new Date().toISOString().slice(0, 10)}-${git.head}`;
225
+ const approaches = commits.map((c) => c.message).filter(Boolean);
226
+ const session = {
227
+ sessionId,
228
+ timestamp: new Date().toISOString(),
229
+ span: {
230
+ from: stamp && stamp.head ? stamp.head : `HEAD~${cfg.lookback}`,
231
+ to: git.head,
232
+ },
233
+ problems: [],
234
+ approaches,
235
+ wrongTurns: [],
236
+ solutions: [],
237
+ patterns: [],
238
+ matched_primitives: [],
239
+ metrics: { commits: commits.length },
240
+ };
241
+
242
+ const outDir = path.join(root, 'docs', 'inference');
243
+ fs.mkdirSync(outDir, { recursive: true });
244
+ const filePath = path.join(outDir, `session-${sessionId.replace(/^session-/, '')}.json`);
245
+ fs.writeFileSync(filePath, `${JSON.stringify(session, null, 2)}\n`);
246
+ fs.writeFileSync(path.join(outDir, 'latest-session.json'), `${JSON.stringify(session, null, 2)}\n`);
247
+ fs.mkdirSync(path.dirname(sessionCaptureStampPath(root)), { recursive: true });
248
+ fs.writeFileSync(
249
+ sessionCaptureStampPath(root),
250
+ `${JSON.stringify({ head: git.head, sessionId, path: filePath, updatedAt: session.timestamp }, null, 2)}\n`,
251
+ );
252
+ return filePath;
253
+ }
254
+
155
255
  export function ensureCursorSessionBoot(root, source = '0xray/cursor-pre-tool-use-boot', extra = {}) {
156
256
  const bootPath = sessionBootPath(root);
157
257
  if (fs.existsSync(bootPath)) {
158
258
  try {
159
259
  const existing = JSON.parse(fs.readFileSync(bootPath, 'utf8'));
160
- if (!cursorBootNeedsRefresh(existing, root)) return bootPath;
260
+ if (!cursorBootNeedsRefresh(existing, root)) {
261
+ maybeCaptureSessionOnHeadMove(root);
262
+ return bootPath;
263
+ }
161
264
  } catch {
162
265
  /* rewrite corrupt or host-mismatched boot */
163
266
  }
@@ -166,7 +269,9 @@ export function ensureCursorSessionBoot(root, source = '0xray/cursor-pre-tool-us
166
269
  host: CURSOR_HOST,
167
270
  ...extra,
168
271
  });
169
- return writeSessionBoot(root, payload) || bootPath;
272
+ const written = writeSessionBoot(root, payload) || bootPath;
273
+ maybeCaptureSessionOnHeadMove(root);
274
+ return written;
170
275
  }
171
276
 
172
277
  export function writeCursorPrecompactReceipt(root, fields) {
@@ -203,6 +203,25 @@ function stationSafeSignals(names) {
203
203
  return out;
204
204
  }
205
205
 
206
+ /** Overlay + factory names on dest. OP-PROC lives here — not on Station.md. */
207
+ function readOpProcNames(root) {
208
+ const dest = join(root, ".xray", "state", "repertoire", "curated_signals.json");
209
+ if (!existsSync(dest)) return [];
210
+ try {
211
+ const data = JSON.parse(readFileSync(dest, "utf8"));
212
+ if (!Array.isArray(data.signals)) return [];
213
+ const names = [];
214
+ for (const signal of data.signals) {
215
+ const name = String(signal && signal.name ? signal.name : "").trim();
216
+ if (!name || name.toLowerCase().startsWith("bedrock-")) continue;
217
+ names.push(name);
218
+ }
219
+ return names;
220
+ } catch {
221
+ return [];
222
+ }
223
+ }
224
+
206
225
  function persistRepertoireWorking(root, snapshot) {
207
226
  try {
208
227
  mkdirSync(join(root, ".xray", "state"), { recursive: true });
@@ -340,6 +359,8 @@ function applyStationHeat(root, host, extra = {}, existing = {}) {
340
359
  repertoireResume,
341
360
  };
342
361
  if (matchedSignals.length) workingSnapshot.matchedSignals = matchedSignals;
362
+ const opProcNames = readOpProcNames(root);
363
+ if (opProcNames.length) workingSnapshot.opProcNames = opProcNames;
343
364
  const working = persistRepertoireWorking(root, workingSnapshot);
344
365
  if (isCompactHook(extra) && matchedSignals.length) {
345
366
  ingestCompactFeedbackSync(
@@ -519,6 +540,7 @@ module.exports = {
519
540
  isLeftoverMemoryRoutingOff,
520
541
  persistRepertoireWorking,
521
542
  readRepertoireWorking,
543
+ readOpProcNames,
522
544
  formatWorkingLine,
523
545
  applyStationHeat,
524
546
  extractPreservedStationLines,
@@ -18,6 +18,7 @@ export const readPlanLine = impl.readPlanLine;
18
18
  export const buildRepertoireResume = impl.buildRepertoireResume;
19
19
  export const persistRepertoireWorking = impl.persistRepertoireWorking;
20
20
  export const readRepertoireWorking = impl.readRepertoireWorking;
21
+ export const readOpProcNames = impl.readOpProcNames;
21
22
  export const formatWorkingLine = impl.formatWorkingLine;
22
23
  export const applyStationHeat = impl.applyStationHeat;
23
24
  export const extractPreservedStationLines = impl.extractPreservedStationLines;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.16",
3
+ "version": "4.0.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -67,13 +67,13 @@ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `g
67
67
  - **Peer test:** another instance with only worn 0xRay continues the ticket. No command stream.
68
68
  - **Wear first:** Read `.xray/state/STATION.md`. Same cloud. Same critic (resume only). Dummy Reads Station.
69
69
  - **Dummy tests `SKILLS.md`:** a suited dummy proves the worn catalog. Same-sess bodies keep context and hold a Station card.
70
- - **Ship track:** always branch + worktree/aside + PR. Docs as you go. Builds. Rollback = close the PR.
70
+ - **Ship track:** always branch + worktree/aside + PR. Docs as you go. Builds. Rollback = close the PR. **Subject review. Fix n ship.** After critic PASS, review dest/domain, close leftovers, then mill-gate D. PASS is not ship. **Groover is not Repertoire.**
71
71
  - **Publish:** stay logged in (do not `npm logout`). Every time run `npm publish --access public` in the live TTY. Paste the clickable `auth/cli` URL. No Enter, no VM browser, no subagent, no 6-digit code in chat. Poll `npm view` until live. Then prove **fresh** and **upgrade** registry installs. `npx 0xray validate` is the wear check (not leftover init.sh). `npm view` is not an install.
72
72
  - **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
73
- - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes.
73
+ - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
74
74
  - **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
75
75
  - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
76
- - **Close:** loop until Station is done. Compact: Station survives the cut. Repertoire keeps names.
76
+ - **Close:** loop until Station is done. Compact: Station survives the cut. Overlay dest names are OP-PROC — reload `repertoire-working.json` `opProcNames`, not Station.
77
77
  - **Board:** critic Strict comments; forge implements; lead stays main thread.
78
78
  - **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
79
79
  - **Ship matrix:** `LEAD-CADENCE.md` Decision matrix — A PR+CI · B pack · C `release:docs-check` · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.16",
3
+ "version": "4.0.17",
4
4
  "description": "Multi-agent orchestration and Codex governance for OpenCode, Hermes, Grok Build, and OpenClaw",
5
5
  "readme": "README.md",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.16",
3
+ "version": "4.0.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -67,13 +67,13 @@ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `g
67
67
  - **Peer test:** another instance with only worn 0xRay continues the ticket. No command stream.
68
68
  - **Wear first:** Read `.xray/state/STATION.md`. Same cloud. Same critic (resume only). Dummy Reads Station.
69
69
  - **Dummy tests `SKILLS.md`:** a suited dummy proves the worn catalog. Same-sess bodies keep context and hold a Station card.
70
- - **Ship track:** always branch + worktree/aside + PR. Docs as you go. Builds. Rollback = close the PR.
70
+ - **Ship track:** always branch + worktree/aside + PR. Docs as you go. Builds. Rollback = close the PR. **Subject review. Fix n ship.** After critic PASS, review dest/domain, close leftovers, then mill-gate D. PASS is not ship. **Groover is not Repertoire.**
71
71
  - **Publish:** stay logged in (do not `npm logout`). Every time run `npm publish --access public` in the live TTY. Paste the clickable `auth/cli` URL. No Enter, no VM browser, no subagent, no 6-digit code in chat. Poll `npm view` until live. Then prove **fresh** and **upgrade** registry installs. `npx 0xray validate` is the wear check (not leftover init.sh). `npm view` is not an install.
72
72
  - **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
73
- - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes.
73
+ - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
74
74
  - **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
75
75
  - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
76
- - **Close:** loop until Station is done. Compact: Station survives the cut. Repertoire keeps names.
76
+ - **Close:** loop until Station is done. Compact: Station survives the cut. Overlay dest names are OP-PROC — reload `repertoire-working.json` `opProcNames`, not Station.
77
77
  - **Board:** critic Strict comments; forge implements; lead stays main thread.
78
78
  - **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
79
79
  - **Ship matrix:** `LEAD-CADENCE.md` Decision matrix — A PR+CI · B pack · C `release:docs-check` · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.16",
3
+ "version": "4.0.17",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",