0xray 4.0.21 → 4.0.23

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 (103) hide show
  1. package/.grok-plugin/plugin.json +1 -1
  2. package/.opencode/skills/hermes-agent/SKILL.md +1 -1
  3. package/.opencode/skills/orchestrator/SKILL.md +28 -6
  4. package/.xray/features.json +1 -1
  5. package/AGENTS-consumer.md +11 -11
  6. package/AGENTS.md +8 -8
  7. package/README.md +27 -27
  8. package/SKILLS.md +1 -1
  9. package/dist/AGENTS.md +8 -8
  10. package/dist/CHANGELOG.md +98 -0
  11. package/dist/README.md +27 -27
  12. package/dist/SKILLS.md +1 -1
  13. package/dist/governance/governance-core.d.ts +2 -1
  14. package/dist/governance/governance-core.js +20 -11
  15. package/dist/governance/governance-service.js +9 -7
  16. package/dist/inference/inference-accumulator.js +36 -4
  17. package/dist/inference/inference-cycle.d.ts +12 -0
  18. package/dist/inference/inference-cycle.js +180 -21
  19. package/dist/inference/inference-proposal-generator.js +148 -5
  20. package/dist/inference/session-capture.d.ts +4 -0
  21. package/dist/integrations/cursor/README.md +1 -1
  22. package/dist/integrations/cursor/hooks/cursor-hook-utils.js +19 -0
  23. package/dist/integrations/cursor/hooks/pre-tool-use.js +2 -1
  24. package/dist/integrations/governance/index.d.ts +5 -0
  25. package/dist/integrations/governance/index.js +22 -2
  26. package/dist/integrations/governance/types.d.ts +11 -0
  27. package/dist/integrations/governance/types.js +16 -0
  28. package/dist/integrations/hooks/station-hook-runtime.cjs +90 -30
  29. package/dist/integrations/hooks/station-hook-runtime.mjs +1 -0
  30. package/dist/integrations/hooks/station-memory-ingest.mjs +4 -2
  31. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  32. package/dist/mcps/governance.server.d.ts +2 -0
  33. package/dist/mcps/governance.server.js +12 -1
  34. package/dist/memory-routing/index.d.ts +1 -1
  35. package/dist/memory-routing/index.js +1 -1
  36. package/dist/memory-routing/lesson-pickup.d.ts +2 -0
  37. package/dist/memory-routing/lesson-pickup.js +57 -0
  38. package/dist/memory-routing/provider-loader.d.ts +8 -1
  39. package/dist/memory-routing/provider-loader.js +49 -1
  40. package/dist/memory-routing/provider-registry.d.ts +7 -2
  41. package/dist/memory-routing/provider-registry.js +26 -6
  42. package/dist/memory-routing/record-lesson.d.ts +16 -0
  43. package/dist/memory-routing/record-lesson.js +26 -0
  44. package/dist/memory-routing/types.d.ts +15 -0
  45. package/dist/nucleus/thin-dispatch.d.ts +2 -0
  46. package/dist/nucleus/thin-dispatch.js +14 -4
  47. package/dist/processors/implementations/agents-md-validation-processor.js +1 -1
  48. package/dist/skills/hermes-agent/SKILL.md +1 -1
  49. package/dist/skills/orchestrator/SKILL.md +28 -6
  50. package/package.json +2 -2
  51. package/scripts/foundry/CHANGELOG.md +2 -0
  52. package/scripts/foundry/README.md +2 -2
  53. package/scripts/foundry/cli.mjs +1 -1
  54. package/scripts/foundry/inspect.mjs +160 -5
  55. package/scripts/foundry/plant/skills/inspect/SKILL.md +2 -0
  56. package/scripts/foundry/reconcile-version.mjs +23 -1
  57. package/scripts/foundry/release.mjs +1 -1
  58. package/scripts/foundry/validate-release-docs.mjs +24 -20
  59. package/scripts/foundry/version-manager.mjs +180 -7
  60. package/scripts/mjs/test-consumer-readiness.mjs +10 -3
  61. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  62. package/src/mcps/governance.server.ts +12 -1
  63. package/src/skills/hermes-agent/SKILL.md +1 -1
  64. package/src/skills/orchestrator/SKILL.md +28 -6
  65. package/vendor/@0xray/repertoire/data/stack-overlay.json +156 -3
  66. package/vendor/@0xray/repertoire/data/subject-overlay.json +3 -3
  67. package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts +4 -0
  68. package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +1 -1
  69. package/vendor/@0xray/repertoire/dist/RepertoireService.js +7 -6
  70. package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +1 -1
  71. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +1 -1
  72. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js +10 -11
  73. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +1 -1
  74. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +1 -1
  75. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js +5 -0
  76. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +1 -1
  77. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +1 -1
  78. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js +16 -0
  79. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +1 -1
  80. package/vendor/@0xray/repertoire/dist/paths.d.ts +3 -3
  81. package/vendor/@0xray/repertoire/dist/paths.d.ts.map +1 -1
  82. package/vendor/@0xray/repertoire/dist/paths.js +66 -4
  83. package/vendor/@0xray/repertoire/dist/paths.js.map +1 -1
  84. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts +11 -0
  85. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +1 -1
  86. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js +2 -0
  87. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +1 -1
  88. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts +54 -4
  89. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +1 -1
  90. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js +375 -20
  91. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +1 -1
  92. package/vendor/@0xray/repertoire/dist/types.d.ts +21 -0
  93. package/vendor/@0xray/repertoire/dist/types.d.ts.map +1 -1
  94. package/xray/agents_template.md +10 -5
  95. package/xray/features.json +1 -1
  96. package/dist/mcps/shared/prompt-security-validator.d.ts +0 -44
  97. package/dist/mcps/shared/prompt-security-validator.js +0 -148
  98. package/dist/mcps/shared/security-scanner.d.ts +0 -119
  99. package/dist/mcps/shared/security-scanner.js +0 -429
  100. package/dist/scripts/activate-kernel-pipeline.d.ts +0 -7
  101. package/dist/scripts/activate-kernel-pipeline.js +0 -101
  102. package/src/mcps/shared/prompt-security-validator.ts +0 -199
  103. package/src/mcps/shared/security-scanner.ts +0 -599
@@ -33,6 +33,17 @@ export interface MemoryTaskConfidence {
33
33
  complexityBoost: number;
34
34
  recommendedAgent: string | null;
35
35
  }
36
+ export interface MemoryLessonLine {
37
+ taskId: string;
38
+ decision: 'success' | 'failure';
39
+ text: string;
40
+ at: string;
41
+ }
42
+ export interface MemorySignalLessons {
43
+ name: string;
44
+ definition: string;
45
+ lines: MemoryLessonLine[];
46
+ }
36
47
  export interface MemoryRoutingContext {
37
48
  providerId: string;
38
49
  matchedSignals: string[];
@@ -41,6 +52,8 @@ export interface MemoryRoutingContext {
41
52
  synthesisAvailable: boolean;
42
53
  signalConfidences?: Record<string, number>;
43
54
  avgMatchConfidence?: number;
55
+ /** Laws above the floor, with the graded lines a wake reads. */
56
+ lessons?: MemorySignalLessons[];
44
57
  }
45
58
  export interface MemoryInheritedContext {
46
59
  providerId: string;
@@ -67,6 +80,8 @@ export interface OrchestratorFeedbackEntry {
67
80
  success: boolean;
68
81
  durationMs: number;
69
82
  dynamoResult?: Record<string, unknown>;
83
+ /** Approaches, solutions, or the wrong turn from the sessions that named the law. */
84
+ lesson?: string;
70
85
  }
71
86
  export interface MemoryRoutingProviderConfig {
72
87
  [key: string]: unknown;
@@ -7,6 +7,7 @@
7
7
  * Import from here or from delegation/index.ts (which re-exports these).
8
8
  */
9
9
  import { ComplexityMetrics, ComplexityScore, ComplexityLevel, ComplexityThresholds } from "../delegation/complexity-core.js";
10
+ import type { MemorySignalLessons } from "../memory-routing/types.js";
10
11
  export type { ComplexityMetrics, ComplexityScore, ComplexityLevel, ComplexityThresholds };
11
12
  export declare const NUCLEUS_THIN_DISPATCH_VERSION = "0.1.0";
12
13
  /**
@@ -29,5 +30,6 @@ export declare function scoreAndRoute(operation: string, context: unknown, thres
29
30
  providerId: string;
30
31
  adjustedScore: number;
31
32
  signals: string[];
33
+ lessons?: MemorySignalLessons[];
32
34
  };
33
35
  };
@@ -7,9 +7,9 @@
7
7
  * Import from here or from delegation/index.ts (which re-exports these).
8
8
  */
9
9
  import { frameworkLogger } from "../core/framework-logger.js";
10
- import { getLevelFromScore, getAgentForTier, levelToTier, } from "../delegation/complexity-core.js";
10
+ import { getLevelFromScore, getAgentForTier, getAgentCountForLevel, getStrategyForLevel, levelToTier, } from "../delegation/complexity-core.js";
11
11
  import { ComplexityAnalyzer } from "../delegation/complexity-analyzer.js";
12
- import { getMemoryRoutingProviderSync, initializeMemoryRouting, } from "../memory-routing/index.js";
12
+ import { ensureMemoryRoutingProviderSync, initializeMemoryRouting, } from "../memory-routing/index.js";
13
13
  initializeMemoryRouting();
14
14
  export const NUCLEUS_THIN_DISPATCH_VERSION = "0.1.0";
15
15
  /**
@@ -18,6 +18,9 @@ export const NUCLEUS_THIN_DISPATCH_VERSION = "0.1.0";
18
18
  */
19
19
  export function scoreComplexity(operation, context, thresholds) {
20
20
  const analyzer = new ComplexityAnalyzer();
21
+ if (thresholds) {
22
+ analyzer.setThresholds(thresholds);
23
+ }
21
24
  const metrics = analyzer.analyzeComplexity(operation, context);
22
25
  const score = analyzer.calculateComplexityScore(metrics);
23
26
  frameworkLogger.log("nucleus-thin-dispatch", "score-complexity", "info", {
@@ -55,7 +58,7 @@ export function routeToAgent(scoreOrLevel, level) {
55
58
  export function scoreAndRoute(operation, context, thresholds) {
56
59
  const score = scoreComplexity(operation, context, thresholds);
57
60
  let agent = routeToAgent(score);
58
- const provider = getMemoryRoutingProviderSync();
61
+ const provider = ensureMemoryRoutingProviderSync();
59
62
  let memoryRouting;
60
63
  if (provider.id !== "null") {
61
64
  const resolved = provider.resolveThinDispatch(agent, operation, score.score);
@@ -64,6 +67,7 @@ export function scoreAndRoute(operation, context, thresholds) {
64
67
  providerId: resolved.context.providerId,
65
68
  adjustedScore: resolved.adjustedScore,
66
69
  signals: resolved.context.matchedSignals,
70
+ ...(resolved.context.lessons ? { lessons: resolved.context.lessons } : {}),
67
71
  };
68
72
  const adjustedLevel = getLevelFromScore(resolved.adjustedScore, thresholds);
69
73
  frameworkLogger.log("nucleus-thin-dispatch", "memory-routing", "info", {
@@ -76,7 +80,13 @@ export function scoreAndRoute(operation, context, thresholds) {
76
80
  signals: resolved.context.matchedSignals,
77
81
  });
78
82
  return {
79
- score: { ...score, score: resolved.adjustedScore, level: adjustedLevel },
83
+ score: {
84
+ ...score,
85
+ score: resolved.adjustedScore,
86
+ level: adjustedLevel,
87
+ recommendedStrategy: getStrategyForLevel(adjustedLevel),
88
+ estimatedAgents: getAgentCountForLevel(adjustedLevel),
89
+ },
80
90
  agent,
81
91
  memoryRouting,
82
92
  };
@@ -224,7 +224,7 @@ export class AgentsMdValidationProcessor {
224
224
  "",
225
225
  "## Codex",
226
226
  "",
227
- `0xRay enforces Universal Development Codex (60 terms) for systematic error prevention.`,
227
+ `0xRay enforces Universal Development Codex (69 terms) for systematic error prevention.`,
228
228
  "",
229
229
  ].join("\n"),
230
230
  "## CLI Commands": [
@@ -64,7 +64,7 @@ Returns: pass/fail with per-file results and violations.
64
64
 
65
65
  ### xray_codex_check
66
66
 
67
- Validate code against the 60-term Universal Development Codex. Checks error-handling, type-safety, performance, security, architecture.
67
+ Validate code against the 69-term Universal Development Codex. Checks error-handling, type-safety, performance, security, architecture.
68
68
 
69
69
  ```
70
70
  xray_codex_check(code="const x: any = foo()", operation="create")
@@ -7,15 +7,15 @@ version: 1.0.0
7
7
  schema_version: "1.0"
8
8
  tags: [orchestration, orchestrator, lead-dev]
9
9
  capabilities:
10
- - coordinate_agents
11
- - delegate_tasks
12
- - manage_workflow
10
+ - coordinate_agents
11
+ - delegate_tasks
12
+ - manage_workflow
13
13
  dependencies: []
14
14
 
15
15
  mcp:
16
- orchestrator:
17
- command: node
18
- args: [node_modules/0xray/dist/mcps/orchestrator.server.js]
16
+ orchestrator:
17
+ command: node
18
+ args: [node_modules/0xray/dist/mcps/orchestrator.server.js]
19
19
  ---
20
20
 
21
21
  # Orchestrator Skill — includes lead-dev operating model
@@ -64,6 +64,10 @@ Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
64
64
 
65
65
  The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/ops/LEAD-CADENCE.md`.
66
66
 
67
+ Jargon is not the job. Review and cadence ask whether the change works. Do not spend the loop reciting dest names, mill liturgy, or host mantras.
68
+
69
+ - **Feat rebase:** when the mandated work turns into mantra, or the job has split across planes that no longer share one present, stop. Go up a level and answer the original message again from this seat. Do not continue the side thread and call that the job.
70
+
67
71
  - **Peer test:** another instance with only worn 0xRay continues the ticket. No command stream.
68
72
  - **Wear first:** Read `.xray/state/STATION.md`. Same cloud. Same critic (resume only). Dummy Reads Station.
69
73
  - **Dummy tests `SKILLS.md`:** a suited dummy proves the worn catalog. Same-sess bodies keep context and hold a Station card.
@@ -73,6 +77,24 @@ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `g
73
77
  - **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
78
  - **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
79
  - **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.
80
+ - **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Capture priority: a law is an invariant you would otherwise re-read the source to relearn. One law per subsystem bone. Heat touches last_seen and does not append a confidence sample, so more hits do not raise conviction. Heat touches last_seen when the diary contains that signal's name or a local clause of four definition content words; two definition words are not a hit; the same words scattered through a long diary are not a hit; a weak session score is not lifted to 0.55 and a sample below 0.55 is not recorded. Constructing the organ does not append workspace samples. Hero names: `heat-is-not-conviction`, `inference-cycle-invariant`, `governance-vote-invariant`, `thin-dispatch-invariant`. Repertoire mergeStackOverlay refreshes a changed stack definition and keeps observation stats. A floor observation count does not change a route. Feedback moves conviction by a tenth, and a failure can leave 0.55. learned-conviction.json beside dest restores that average when a wake flattens it to 0.55. It does not store the observation count.
81
+ - **Cold brief:** a new critic or any new subagent that does not already have this thread gets the latest commit SHA on the branch under review (fetch it; do not reuse an earlier SHA from a previous pass) and the Station card (`.xray/state/STATION.md`: intent, plan, git). If the card is missing, give branch + HEAD + what just changed. If the branch moves after you brief them, send the new SHA before they verdict.
82
+ - **Control:** The lead keeps control. Do not assume the subagent has the context. Give the duty, the latest SHA, the Station card, and the laws that apply. The subagent wears the applicable 0xRay suit before it works: the tree under review, built and installed. An older published package is not that suit. The lead checks the result.
83
+
84
+ ### Engine cadence
85
+
86
+ This suite is the engine that builds the engine. When a seat sees OP-PROC, write it onto these existing surfaces in the same wake. Do not open a new skill.
87
+
88
+ 1. Change the engine with precision.
89
+ 2. Ship it local: build and install the tree. A live npm version stays live. Once a version is live, the stamper strips every present-tense patch pin from shipped guides and shipped OP-PROC, or reconcile advances the next cut. The stamper does not edit Station, NOTES, dest, or node_modules. It does not publish.
90
+ 3. Test the change.
91
+ 4. Run another deep review of the diff you just made.
92
+ 5. Monitor long-term memory (dest name count and whether observations are the only growth) and short-term memory (Station: intent, plan, git).
93
+ 6. Ship the PR.
94
+
95
+ ### Planes
96
+
97
+ Operating planes: code, OP-PROC, model, suit, mill, host, and test/ship. Test/ship is the critical OP-PROC plane. Test then ship is the hero. Ship without that proof is the catastrophe. Long-term memory is the project law list. Each wake refreshes a changed stack definition and keeps observation stats. Heat writes the matched names onto Station, the short-term card that survives compaction. Reactive decisions move out of TypeScript into OP-PROC as the model improves. That move is why the mill and the suit exist. It is not fully proved. Once a version is live, the stamper strips every present-tense patch pin from shipped guides and shipped OP-PROC, or reconcile advances the next cut. The stamper does not edit Station, NOTES, dest, or node_modules. It does not publish. Do not freeze the live cut.
76
98
  - **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
99
  - **Board:** critic Strict comments; forge implements; lead stays main thread.
78
100
  - **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.21",
3
+ "version": "4.0.23",
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",
@@ -106,7 +106,7 @@
106
106
  "debug:inference:force": "XRAY_FORCE_MCP_GOVERNANCE=true XRAY_DEV_PATH=dist node dist/cli/index.js inference:run --force",
107
107
  "validate:full": "npm run validate",
108
108
  "test:unified": "node scripts/test/test-unified-framework.mjs",
109
- "test:consumer": "node scripts/test/test-consumer-readiness.cjs",
109
+ "test:consumer": "node scripts/mjs/test-consumer-readiness.mjs",
110
110
  "config:setup": "node scripts/config/utils.js setup-dev",
111
111
  "monitoring:start": "node scripts/monitoring/daemon.js start",
112
112
  "monitoring:stop": "node scripts/monitoring/daemon.js stop",
@@ -4,6 +4,8 @@
4
4
 
5
5
  Shim `sound-voice.cjs` → `@0xray/blip/sound-voice`. Depend on published `@0xray/blip@^0.1.2`. Foundry stamp stays 0.1.12. Do not vendor mill drawers.
6
6
 
7
+ Inspect `--go` emits a shop-style forge GO receipt (harness profile: bare / suited / partial). Observational by default: Cursor/Grok `hooks.json` bound, Repertoire fastened (`node_modules` or `.xray/state/repertoire`), Station present. `--require-harness=` gates dual-cloud A/B. Vendor Repertoire source and `memory_routing` declaration are not fasten. Not an 8th MCP. Not PPE. Not 5.0.
8
+
7
9
  ## [0.1.12] - 2026-09-18
8
10
 
9
11
  Fasten is foundry-plant/0: mill packages declare plants in package.json (`mill.protocol`, prefix selection when skills/agents are omitted) and foundry copies organs from that package. Builtin catalog is mill+inspect only; foundry does not catalog mill organs. `foundry.json` `"plant": "blip"|"sound"` are package aliases for `@0xray/blip`, not skill lists. Unknown mill packages fail closed (`npm i`). Inventory records `millPackage` and `millProtocol` when a mill package was used.
@@ -23,7 +23,7 @@ npx @0xray/foundry release [patch|minor|major] --i-mean-it
23
23
  npx @0xray/foundry release --publish-only --dry-run
24
24
  npx @0xray/foundry release --publish-only --i-mean-it
25
25
  npx @0xray/foundry mint
26
- npx @0xray/foundry inspect [--skip-live]
26
+ npx @0xray/foundry inspect [--skip-live] [--go] [--go-out PATH] [--require-harness=bare|suited|partial]
27
27
  npx @0xray/foundry sound render [--brief TEXT] [--genre ambient|techno|jazz]
28
28
  npx @0xray/foundry sound inspect
29
29
  npx @0xray/foundry sound mix
@@ -39,7 +39,7 @@ npx @0xray/foundry hooks
39
39
 
40
40
  `FOUNDRY_ROOT` overrides cwd (the repo being milled).
41
41
 
42
- `gate` is build + test + docs-check. `docs-build` runs Docusaurus on the 0xray exo (`docs-site/`); stranger mills skip. `inspect` runs the six mill checks (diff, plant vs worn, receipt, CI, live tarball GET, isolated HOME). Mint fails on a costume dump. Isolated HOME skips machine `~/.grok`. Shared HOME last-mile dest is project `.grok/plugins/0xray` (no last-wins machine plugin). `ci` reports GitHub Actions (no auto-push). `hooks` installs git pre/post hooks. GitHub `0xRay CI/CD` is the mill gate on `main`. `Deploy Docs` is the mill Pages put.
42
+ `gate` is build + test + docs-check. `docs-build` runs Docusaurus on the 0xray exo (`docs-site/`); stranger mills skip. `inspect` runs the six mill checks (diff, plant vs worn, receipt, CI, live tarball GET, isolated HOME) plus observational harness (Cursor/Grok hooks bound, Repertoire fastened, Station present). `--go` emits a shop-style forge GO receipt; `--require-harness=bare|suited|partial` turns that observation into a gate. Mint fails on a costume dump. Isolated HOME skips machine `~/.grok`. Shared HOME last-mile dest is project `.grok/plugins/0xray` (no last-wins machine plugin). `ci` reports GitHub Actions (no auto-push). `hooks` installs git pre/post hooks. GitHub `0xRay CI/CD` is the mill gate on `main`. `Deploy Docs` is the mill Pages put.
43
43
 
44
44
  `docs-check` and `gate` run **full** 0xRay corpus only when the milled `package.json` name is `0xray` and `docs-site/` exists. Otherwise **light**: `package.json` + CHANGELOG.
45
45
 
@@ -29,7 +29,7 @@ const HELP =
29
29
  "Mill, not exo. FOUNDRY_ROOT overrides cwd (the repo being milled).\n" +
30
30
  "release bumps/commits/pushes/publishes the milled cwd — pass --dry-run or --i-mean-it (or FOUNDRY_RELEASE=1).\n" +
31
31
  "Mint fastens the requested factory plant (default mill; foundry.json plant: sound|blip turns mill off), then inspect.\n" +
32
- "inspect runs mill checks plus, on a sound seat, last bed receipt PASS/FAIL; on a blip seat, last blip receipt.\n" +
32
+ "inspect runs mill checks plus, on a sound seat, last bed receipt PASS/FAIL; on a blip seat, last blip receipt. Observational harness (hooks / Repertoire / Station). --go emits a forge GO receipt. Not an 8th MCP.\n" +
33
33
  "sound render|inspect|mix is the factory-sound plant (brief → seed → genre → wav → metrics; mix levels every variation). Sibling to mill, not a mill copy.\n" +
34
34
  "blip render|inspect|vibe|look is the factory-blip plant (brief → seed → still|motion:<id> → 4.44s mp4; vibe is stamp density, look is the friend hitting replay, ship bar 8). Sibling to mill + sound.\n" +
35
35
  "gate is build+test. docs-build is Docusaurus on the 0xray exo. ci reports GitHub Actions (no auto-push). hooks installs git pre/post hooks.\n";
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Mill inspect organ. Runs the six checks. Not an 8th MCP. Not PPE.
3
+ * Mill inspect organ. Runs the six plant checks plus observational harness.
4
+ * Not an 8th MCP. Not PPE. Does not fasten hooks or Repertoire.
4
5
  *
5
- * npx @0xray/foundry inspect [--skip-live]
6
+ * npx @0xray/foundry inspect [--skip-live] [--go] [--go-out PATH]
7
+ * [--require-harness=bare|suited|partial] [--goal TEXT]
6
8
  */
7
9
 
8
10
  import { spawnSync } from "node:child_process";
@@ -63,6 +65,140 @@ function readJson(file) {
63
65
  }
64
66
  }
65
67
 
68
+ const HARNESS_PROFILES = new Set(["bare", "suited", "partial"]);
69
+
70
+ export function parseInspectArgs(argv = process.argv.slice(2)) {
71
+ const out = {
72
+ skipLive: false,
73
+ go: false,
74
+ goOut: null,
75
+ requireHarness: null,
76
+ goal: null,
77
+ };
78
+ for (let i = 0; i < argv.length; i += 1) {
79
+ const arg = argv[i];
80
+ if (arg === "--skip-live") out.skipLive = true;
81
+ else if (arg === "--go") out.go = true;
82
+ else if (arg === "--go-out") out.goOut = argv[++i] || null;
83
+ else if (arg.startsWith("--go-out=")) out.goOut = arg.slice("--go-out=".length);
84
+ else if (arg === "--require-harness") out.requireHarness = argv[++i] || null;
85
+ else if (arg.startsWith("--require-harness=")) {
86
+ out.requireHarness = arg.slice("--require-harness=".length);
87
+ } else if (arg === "--goal") out.goal = argv[++i] || null;
88
+ else if (arg.startsWith("--goal=")) out.goal = arg.slice("--goal=".length);
89
+ }
90
+ if (out.goOut) out.go = true;
91
+ return out;
92
+ }
93
+
94
+ function hooksFileBound(file) {
95
+ if (!fs.existsSync(file)) return false;
96
+ const json = readJson(file);
97
+ const hooks = json?.hooks;
98
+ if (!hooks || typeof hooks !== "object") return false;
99
+ return Object.values(hooks).some(
100
+ (list) =>
101
+ Array.isArray(list) &&
102
+ list.some((entry) => typeof entry?.command === "string" && entry.command.trim()),
103
+ );
104
+ }
105
+
106
+ export function classifyHarnessProfile({ hooksBound, repertoireFastened, stationPresent }) {
107
+ if (!hooksBound && !repertoireFastened && !stationPresent) return "bare";
108
+ if (hooksBound && repertoireFastened) return "suited";
109
+ return "partial";
110
+ }
111
+
112
+ export function probeHarness(root) {
113
+ const cursorHooks = path.join(root, ".cursor", "hooks.json");
114
+ const grokHooks = path.join(root, ".grok", "plugins", "0xray", "hooks", "hooks.json");
115
+ const grokPluginHooks = path.join(root, ".grok-plugin", "hooks", "hooks.json");
116
+ const hooks = {
117
+ cursor: hooksFileBound(cursorHooks),
118
+ grok: hooksFileBound(grokHooks) || hooksFileBound(grokPluginHooks),
119
+ };
120
+ hooks.bound = Boolean(hooks.cursor || hooks.grok);
121
+
122
+ const repertoire = {
123
+ nodeModules: fs.existsSync(path.join(root, "node_modules", "@0xray", "repertoire")),
124
+ state: fs.existsSync(path.join(root, ".xray", "state", "repertoire")),
125
+ vendorSource: fs.existsSync(path.join(root, "vendor", "@0xray", "repertoire")),
126
+ };
127
+ repertoire.fastened = Boolean(repertoire.nodeModules || repertoire.state);
128
+
129
+ const features =
130
+ readJson(path.join(root, ".xray", "features.json")) ||
131
+ readJson(path.join(root, "xray", "features.json"));
132
+ repertoire.memoryRoutingDeclared = features?.memory_routing?.provider === "repertoire";
133
+
134
+ const stationPresent = fs.existsSync(path.join(root, ".xray", "state", "STATION.md"));
135
+ const profile = classifyHarnessProfile({
136
+ hooksBound: hooks.bound,
137
+ repertoireFastened: repertoire.fastened,
138
+ stationPresent,
139
+ });
140
+
141
+ return {
142
+ id: "harness",
143
+ hooks,
144
+ repertoire,
145
+ station: { present: stationPresent },
146
+ profile,
147
+ };
148
+ }
149
+
150
+ export function checkHarness(root, requireHarness = null) {
151
+ const probe = probeHarness(root);
152
+ if (requireHarness && !HARNESS_PROFILES.has(requireHarness)) {
153
+ return {
154
+ ...probe,
155
+ ok: false,
156
+ require: requireHarness,
157
+ detail: `unknown --require-harness=${requireHarness} (bare|suited|partial)`,
158
+ };
159
+ }
160
+ if (requireHarness && probe.profile !== requireHarness) {
161
+ return {
162
+ ...probe,
163
+ ok: false,
164
+ require: requireHarness,
165
+ detail: `harness profile ${probe.profile} != required ${requireHarness}`,
166
+ };
167
+ }
168
+ return {
169
+ ...probe,
170
+ ok: true,
171
+ require: requireHarness,
172
+ skipped: !requireHarness,
173
+ detail: requireHarness ? null : "observational — pass --require-harness to gate",
174
+ };
175
+ }
176
+
177
+ function gitRemote(root) {
178
+ const remote = spawnSync("git", ["config", "--get", "remote.origin.url"], {
179
+ cwd: root,
180
+ encoding: "utf8",
181
+ });
182
+ if (remote.error || remote.status !== 0) return null;
183
+ return (remote.stdout || "").trim() || null;
184
+ }
185
+
186
+ export function buildForgeGo(root, harness, opts = {}) {
187
+ return {
188
+ kind: "forge-go",
189
+ mill: "inspect",
190
+ profile: harness.profile,
191
+ hooksBound: Boolean(harness.hooks?.bound),
192
+ repertoireFastened: Boolean(harness.repertoire?.fastened),
193
+ stationPresent: Boolean(harness.station?.present),
194
+ require: harness.require || null,
195
+ ok: harness.ok !== false,
196
+ goal: opts.goal || process.env.FOUNDRY_GO_GOAL || null,
197
+ repo: gitRemote(root),
198
+ generatedAt: new Date().toISOString(),
199
+ };
200
+ }
201
+
66
202
  function checkDiff(root) {
67
203
  const status = spawnSync("git", ["status", "-sb"], { cwd: root, encoding: "utf8" });
68
204
  if (status.error || status.status === 128) {
@@ -412,6 +548,9 @@ export async function inspectSuit(root, opts = {}) {
412
548
  const skipLive = Boolean(opts.skipLive);
413
549
  const env = opts.env || process.env;
414
550
  const machineHome = opts.machineHome || mint.machineHome();
551
+ const requireHarness = opts.requireHarness || null;
552
+ const go = Boolean(opts.go);
553
+ const goal = opts.goal || null;
415
554
 
416
555
  const checks = [];
417
556
  checks.push(checkDiff(root));
@@ -445,22 +584,38 @@ export async function inspectSuit(root, opts = {}) {
445
584
  }
446
585
 
447
586
  checks.push(checkIsolatedHome(root, env, machineHome));
587
+ checks.push(checkHarness(root, requireHarness));
448
588
 
449
589
  const failed = checks.filter((c) => c.ok === false);
450
590
  const receipt = checks.find((c) => c.id === "receipt") || {};
451
- return {
591
+ const harness = checks.find((c) => c.id === "harness") || {};
592
+ const report = {
452
593
  ok: failed.length === 0,
453
594
  failed: failed.map((c) => c.id),
454
595
  checks,
455
596
  dna: receipt.dna || null,
456
597
  pack: "0xray-suit",
457
598
  };
599
+ if (go) {
600
+ report.go = buildForgeGo(root, harness, { goal });
601
+ }
602
+ return report;
458
603
  }
459
604
 
460
605
  async function main() {
461
- const skipLive = process.argv.includes("--skip-live");
606
+ const args = parseInspectArgs(process.argv.slice(2));
462
607
  const root = resolveMillRoot();
463
- const report = await inspectSuit(root, { skipLive });
608
+ const report = await inspectSuit(root, {
609
+ skipLive: args.skipLive,
610
+ requireHarness: args.requireHarness,
611
+ go: args.go,
612
+ goal: args.goal,
613
+ });
614
+ if (args.goOut) {
615
+ const dest = path.isAbsolute(args.goOut) ? args.goOut : path.join(root, args.goOut);
616
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
617
+ fs.writeFileSync(dest, `${JSON.stringify(report.go || report, null, 2)}\n`);
618
+ }
464
619
  process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
465
620
  process.exit(report.ok ? 0 : 1);
466
621
  }
@@ -17,6 +17,7 @@ Mill **does** these checks (`npx @0xray/foundry inspect`). Mint fails on a costu
17
17
  4. **CI.** GitHub mill CI report (`.opencode/logs/ci-cd-monitor-report.json`), not a green check in chat. No token is a skip, not a pass invented.
18
18
  5. **Live PUT.** HTTP 200 on the npm `.tgz`. Metadata without a tarball is not shipped.
19
19
  6. **Isolated HOME.** Last-mile dest is project `.grok/plugins/0xray`. Isolated HOME may wear `$HOME/.grok/plugins/0xray` and must not write machine `~/.grok/plugins/0xray`. Shared HOME (passwd `$HOME`) does not last-wins clobber the machine plugin. Mill compares `$HOME` to the passwd home (`os.userInfo().homedir`), not `os.homedir()` (which follows `$HOME`).
20
+ 7. **Harness (observational).** Bound Cursor/Grok hooks, fastened Repertoire organ, Station card. Profiles: `bare` / `suited` / `partial`. Does **not** fasten. `--go` prints a forge GO receipt so cloud return is mill, not chat. `--require-harness=bare|suited|partial` fails when the live plant disagrees.
20
21
 
21
22
  ## How to work
22
23
 
@@ -28,6 +29,7 @@ Mill **does** these checks (`npx @0xray/foundry inspect`). Mint fails on a costu
28
29
  ```bash
29
30
  npx @0xray/foundry mint
30
31
  npx @0xray/foundry inspect
32
+ npx @0xray/foundry inspect --skip-live --go --require-harness=bare
31
33
  npx @0xray/foundry ci --report
32
34
  ```
33
35
 
@@ -9,6 +9,9 @@
9
9
  * npx @0xray/foundry reconcile --check
10
10
  * npx @0xray/foundry reconcile patch
11
11
  * npx @0xray/foundry reconcile patch --apply
12
+ *
13
+ * --apply writes package.json and the package-lock.json version fields.
14
+ * --check fails when the lock does not match package.json.
12
15
  */
13
16
 
14
17
  import { execSync } from "child_process";
@@ -16,6 +19,7 @@ import fs from "fs";
16
19
  import path from "path";
17
20
  import { fileURLToPath } from "url";
18
21
  import { readRootPackage, resolveMillRoot } from "./mill-root.mjs";
22
+ import { packageLockVersions, syncPackageLockVersion } from "./version-manager.mjs";
19
23
 
20
24
  const rootDir = resolveMillRoot();
21
25
  const pkgPath = path.join(rootDir, "package.json");
@@ -101,8 +105,12 @@ function main() {
101
105
  }
102
106
 
103
107
  console.log("\n=== Version Reconcile ===\n");
108
+ const lockBefore = packageLockVersions(rootDir);
104
109
  console.log(` npm registry : ${npm}`);
105
110
  console.log(` package.json : ${local}`);
111
+ console.log(
112
+ ` package-lock : ${lockBefore ? `${lockBefore.root} / ${lockBefore.pkg}` : "(none)"}`,
113
+ );
106
114
  console.log(` latest tag : ${tag ? `v${tag}` : "(none)"}`);
107
115
  if (bumpType) {
108
116
  console.log(` bump ${bumpType} : ${target} (from baseline ${baseline})`);
@@ -112,7 +120,13 @@ function main() {
112
120
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
113
121
  pkg.version = target;
114
122
  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
115
- console.log(`\n✅ Updated package.json → ${target}`);
123
+ const synced = syncPackageLockVersion(rootDir, target);
124
+ if (synced === "unmatched") {
125
+ fail(
126
+ `package-lock.json version fields were not updated to ${target}. Refusing to leave the lock behind package.json.`,
127
+ );
128
+ }
129
+ console.log(`\n✅ Updated package.json and package-lock.json → ${target}`);
116
130
  }
117
131
 
118
132
  if (!checkMode) {
@@ -129,6 +143,14 @@ function main() {
129
143
  fail(`package.json (${local}) must be > npm (${npm}). Run: npx @0xray/foundry reconcile patch --apply`);
130
144
  }
131
145
 
146
+ const pkgVersion = readLocalVersion();
147
+ const lockNow = packageLockVersions(rootDir);
148
+ if (lockNow && (lockNow.root !== pkgVersion || lockNow.pkg !== pkgVersion)) {
149
+ fail(
150
+ `package-lock.json (${lockNow.root} / ${lockNow.pkg}) must match package.json (${pkgVersion}). The bumper writes both: npx @0xray/foundry reconcile patch --apply`,
151
+ );
152
+ }
153
+
132
154
  if (tag && compare(local, tag) < 0) {
133
155
  fail(`package.json (${local}) is behind latest tag v${tag}`);
134
156
  }
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * Canonical 0xRay release script.
5
5
  *
6
- * 1. Bump version from npm registry baseline (reconcile-version)
6
+ * 1. Bump version from npm registry baseline (reconcile-version writes package.json and package-lock.json)
7
7
  * 2. Release artifacts (CHANGELOG / README / AGENTS / docs) — before gate so docs tests pass
8
8
  * 3. Release gate (build + test + consumer smoke)
9
9
  * 4. Commit release artifacts → push
@@ -18,6 +18,7 @@ import {
18
18
  DOCS_SITE_HEADER_FILES,
19
19
  getFrameworkCounts,
20
20
  getReleaseArtifactPaths,
21
+ patchRefStripRelPaths,
21
22
  } from './version-manager.mjs';
22
23
  import { isXrayExoRepo, resolveMillRoot } from './mill-root.mjs';
23
24
 
@@ -31,30 +32,13 @@ function kernelLineHasPatchStamp(content) {
31
32
 
32
33
  /**
33
34
  * Present-tense cut pins. Keep: package.json, CHANGELOG, stamped JSON,
34
- * features-since headings. Rip from guides, Station, OP-PROC.
35
+ * features-since headings. The check set is the stamper set: shipped guides
36
+ * and shipped OP-PROC, including the mill-gate skill. Seat memory is not in it.
35
37
  */
36
38
  const PRESENT_TENSE_PATCH_RE =
37
39
  /This cut is|Do not republish \d+\.\d+\.\d+|0xray@\d+\.\d+\.\d+|npm is \*\*\d+\.\d+\.\d+\*\*|Product \*\*\d+\.\d+\.\d+\*\* is on npm/;
38
40
 
39
- const NO_PRESENT_TENSE_PATCH = [
40
- 'README.md',
41
- 'AGENTS.md',
42
- 'AGENTS-consumer.md',
43
- 'SKILLS.md',
44
- 'llms.txt',
45
- 'docs-site/docs/architecture/v4-now.md',
46
- 'docs-site/docs/architecture/v4-vision.md',
47
- 'docs-site/docs/guides/memory-wake.md',
48
- 'docs-site/docs/guides/memory-routing.md',
49
- 'docs-site/docs/guides/repertoire.md',
50
- 'docs-site/docs/guides/getting-started.md',
51
- 'docs-site/docs/guides/integrations.md',
52
- 'docs-site/docs/guides/consumer-migration.md',
53
- 'docs-site/docs/mcp/README.md',
54
- 'grok-bot/ops/LEAD-CADENCE.md',
55
- 'grok-bot/AGENTS.md',
56
- 'src/skills/orchestrator/SKILL.md',
57
- ];
41
+ const NO_PRESENT_TENSE_PATCH = patchRefStripRelPaths();
58
42
 
59
43
  function presentTensePatchPinErrors(content) {
60
44
  if (PRESENT_TENSE_PATCH_RE.test(content)) {
@@ -70,6 +54,7 @@ const REQUIRED_GUIDES = [
70
54
  'docs-site/docs/guides/memory-routing.md',
71
55
  'docs-site/docs/guides/aside-context.md',
72
56
  'docs-site/docs/guides/repertoire.md',
57
+ 'docs-site/docs/guides/station-vs-repertoire.md',
73
58
  'docs-site/docs/guides/integrations.md',
74
59
  'docs-site/docs/guides/consumer-migration.md',
75
60
  'docs-site/docs/mcp/README.md',
@@ -87,6 +72,18 @@ function millLawLagErrors(content) {
87
72
  return errors;
88
73
  }
89
74
 
75
+ /** Opt-out is features.json, not package-absence. */
76
+ function repertoireOptOutErrors(content) {
77
+ const errors = [];
78
+ if (/\(no @0xray\/repertoire\)/.test(content)) {
79
+ errors.push('opt-out must not teach package-absence (no @0xray/repertoire)');
80
+ }
81
+ if (/memory_routing stays off/.test(content)) {
82
+ errors.push('opt-out must not teach memory_routing stays off on npm install');
83
+ }
84
+ return errors;
85
+ }
86
+
90
87
  function millPlantMentionErrors(content) {
91
88
  if (!content.includes('mill') || !content.includes('inspect')) {
92
89
  return ['missing mill+inspect plant'];
@@ -357,6 +354,13 @@ export function validateReleaseDocs(rootDir = resolveMillRoot()) {
357
354
  }
358
355
  }
359
356
 
357
+ const stationVs = readFile(rootDir, 'docs-site/docs/guides/station-vs-repertoire.md');
358
+ if (stationVs) {
359
+ for (const e of repertoireOptOutErrors(stationVs)) {
360
+ errors.push(`docs-site/docs/guides/station-vs-repertoire.md: ${e}`);
361
+ }
362
+ }
363
+
360
364
  const docusaurus = readFile(rootDir, 'docs-site/docusaurus.config.ts');
361
365
  if (!docusaurus) {
362
366
  errors.push('docs-site/docusaurus.config.ts: missing');