0xray 4.0.42 → 4.1.1

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 (138) hide show
  1. package/.gitignore.default +4 -1
  2. package/.grok-plugin/plugin.json +1 -1
  3. package/.opencode/skills/orchestrator/SKILL.md +1 -7
  4. package/.plugin/plugin.json +1 -1
  5. package/.xray/features.json +8 -5
  6. package/.xray/features.schema.json +8 -0
  7. package/AGENTS-consumer.md +9 -7
  8. package/AGENTS.md +19 -10
  9. package/LICENSE +1 -1
  10. package/README.md +15 -9
  11. package/SKILLS.md +3 -1
  12. package/dist/.gitignore.default +4 -1
  13. package/dist/AGENTS.md +19 -10
  14. package/dist/CHANGELOG.md +109 -11
  15. package/dist/LICENSE +1 -1
  16. package/dist/README.md +15 -9
  17. package/dist/SKILLS.md +3 -1
  18. package/dist/cli/commands/opencode-install.js +3 -9
  19. package/dist/cli/commands/plugin-commands.d.ts +4 -0
  20. package/dist/cli/commands/plugin-commands.js +84 -41
  21. package/dist/cli/commands/skill-install.js +10 -5
  22. package/dist/cli/goggles-status.d.ts +2 -5
  23. package/dist/cli/goggles-status.js +5 -53
  24. package/dist/cli/index.js +2 -2
  25. package/dist/core/config-loader.js +4 -4
  26. package/dist/core/features-config.d.ts +1 -1
  27. package/dist/core/features-config.js +3 -3
  28. package/dist/enforcement/enforcer-tools.d.ts +1 -1
  29. package/dist/enforcement/enforcer-tools.js +1 -1
  30. package/dist/integrations/cursor/README.md +1 -1
  31. package/dist/integrations/cursor/hooks/hooks.json +6 -3
  32. package/dist/integrations/cursor/hooks/pre-tool-use.js +104 -37
  33. package/dist/integrations/cursor/hooks/xray-cloud-hook.sh +9 -1
  34. package/dist/integrations/grok/grok-cli.js +5 -7
  35. package/dist/integrations/grok/hooks/grok-hook-utils.js +4 -1
  36. package/dist/integrations/grok/hooks/pre-tool-use.js +6 -76
  37. package/dist/integrations/grok/hooks/session-start.js +4 -2
  38. package/dist/integrations/hermes-agent/bridge.mjs +17 -1
  39. package/dist/integrations/hooks/delegation-gate-runtime.mjs +3 -2
  40. package/dist/integrations/hooks/goggles-mcp.mjs +23 -181
  41. package/dist/integrations/hooks/goggles-pipeline.mjs +606 -571
  42. package/dist/integrations/hooks/goggles-planes.json +95 -46
  43. package/dist/integrations/hooks/plates.cjs +84 -0
  44. package/dist/integrations/hooks/pre-tool-speak.mjs +74 -0
  45. package/dist/integrations/hooks/skill-seek.mjs +115 -0
  46. package/dist/integrations/hooks/station-hook-runtime.cjs +4 -1
  47. package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +24 -7
  48. package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +26 -2
  49. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  50. package/dist/memory-routing/plates.d.ts +1 -1
  51. package/dist/memory-routing/plates.js +14 -0
  52. package/dist/monitoring/{nudge-watchdog.d.ts → nudge-monitor.d.ts} +14 -5
  53. package/dist/monitoring/{nudge-watchdog.js → nudge-monitor.js} +42 -17
  54. package/dist/nucleus/thin-dispatch.d.ts +1 -1
  55. package/dist/nucleus/thin-dispatch.js +1 -1
  56. package/dist/nucleus/work-freshness.mjs +10 -0
  57. package/dist/plugin/xray-codex-injection.js +20 -0
  58. package/dist/processors/implementations/nudge-processor.d.ts +1 -1
  59. package/dist/processors/implementations/nudge-processor.js +4 -4
  60. package/dist/skills/orchestrator/SKILL.md +1 -7
  61. package/docs-site/docs/plates/activity-log.md +1 -1
  62. package/docs-site/docs/plates/asides.md +35 -0
  63. package/docs-site/docs/plates/bifrost.md +48 -0
  64. package/docs-site/docs/plates/boot.md +2 -2
  65. package/docs-site/docs/plates/centrifuge.md +1 -1
  66. package/docs-site/docs/plates/confer.md +35 -0
  67. package/docs-site/docs/plates/consumer-mcp.md +35 -0
  68. package/docs-site/docs/plates/cursor-compact.md +1 -1
  69. package/docs-site/docs/plates/delegation-gate.md +35 -0
  70. package/docs-site/docs/plates/dynamo.md +35 -0
  71. package/docs-site/docs/plates/foundry.md +35 -0
  72. package/docs-site/docs/plates/glossary.md +7 -3
  73. package/docs-site/docs/plates/goggles.md +12 -1
  74. package/docs-site/docs/plates/governance.md +1 -1
  75. package/docs-site/docs/plates/grok-compact.md +1 -1
  76. package/docs-site/docs/plates/grokbot.md +3 -1
  77. package/docs-site/docs/plates/ground.md +35 -0
  78. package/docs-site/docs/plates/hermes.md +35 -0
  79. package/docs-site/docs/plates/host-pack.md +1 -1
  80. package/docs-site/docs/plates/house.md +1 -1
  81. package/docs-site/docs/plates/index.md +16 -7
  82. package/docs-site/docs/plates/inference-cycle.md +35 -0
  83. package/docs-site/docs/plates/inference-files.md +1 -1
  84. package/docs-site/docs/plates/kept-line.md +1 -1
  85. package/docs-site/docs/plates/kits.md +1 -1
  86. package/docs-site/docs/plates/lens-gate.md +8 -6
  87. package/docs-site/docs/plates/lens-page.md +1 -1
  88. package/docs-site/docs/plates/memory-recall.md +1 -1
  89. package/docs-site/docs/plates/notes-page.md +2 -2
  90. package/docs-site/docs/plates/openclaw.md +35 -0
  91. package/docs-site/docs/plates/opencode.md +35 -0
  92. package/docs-site/docs/plates/orchestration.md +1 -1
  93. package/docs-site/docs/plates/package-face.md +1 -1
  94. package/docs-site/docs/plates/payload-heat.md +1 -1
  95. package/docs-site/docs/plates/pickup-stamp.md +1 -1
  96. package/docs-site/docs/plates/pre-tool.md +1 -1
  97. package/docs-site/docs/plates/processor.md +1 -1
  98. package/docs-site/docs/plates/record-map.md +1 -1
  99. package/docs-site/docs/plates/reflection-page.md +1 -1
  100. package/docs-site/docs/plates/repertoire.md +35 -0
  101. package/docs-site/docs/plates/reporting.md +1 -1
  102. package/docs-site/docs/plates/review.md +1 -1
  103. package/docs-site/docs/plates/routing.md +1 -1
  104. package/docs-site/docs/plates/session-capture.md +1 -1
  105. package/docs-site/docs/plates/site-manual.md +1 -1
  106. package/docs-site/docs/plates/stamp-plate.md +1 -1
  107. package/docs-site/docs/plates/station-card.md +1 -1
  108. package/docs-site/docs/plates/station-heat.md +1 -1
  109. package/docs-site/docs/plates/suit-organs.md +1 -1
  110. package/docs-site/docs/plates/suit-settings.md +1 -1
  111. package/docs-site/docs/plates/suit-wear.md +1 -1
  112. package/docs-site/docs/plates/suit.md +3 -3
  113. package/docs-site/docs/plates/synthesis.md +35 -0
  114. package/docs-site/docs/plates/temperament.md +35 -0
  115. package/docs-site/docs/plates/trail-state.md +2 -2
  116. package/docs-site/docs/plates/work-fresh.md +1 -1
  117. package/docs-site/docs/plates/write-home.md +1 -1
  118. package/llms.txt +14 -6
  119. package/package.json +3 -3
  120. package/scripts/foundry/README.md +5 -3
  121. package/scripts/foundry/mint-suit.cjs +120 -2
  122. package/scripts/foundry/plant/skills/mill/SKILL.md +1 -1
  123. package/scripts/foundry/reconcile-version.mjs +10 -3
  124. package/scripts/foundry/release-gate.mjs +111 -15
  125. package/scripts/foundry/release.mjs +9 -1
  126. package/scripts/foundry/validate-release-docs.mjs +2 -2
  127. package/scripts/foundry/version-manager.mjs +12 -4
  128. package/scripts/mjs/verify-pipeline-facets.mjs +1 -1
  129. package/scripts/node/install-bridges.cjs +91 -46
  130. package/scripts/node/pack-tmp-suit-proof.mjs +37 -10
  131. package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +26 -2
  132. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  133. package/src/skills/orchestrator/SKILL.md +1 -7
  134. package/vendor/@0xray/repertoire/README.md +1 -1
  135. package/xray/agents_template.md +2 -2
  136. package/xray/features.json +8 -5
  137. package/xray/features.schema.json +8 -0
  138. package/docs-site/docs/plates/live-mesh.md +0 -41
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: Repertoire
3
+ sidebar_label: Repertoire
4
+ ---
5
+
6
+ # Repertoire
7
+
8
+ The memory organ matches named laws.
9
+
10
+ ```
11
+ ┌────────────────────────────────────────────────────────────┐
12
+ │ INPUT LAYER │
13
+ │ ┌────────────────────────────────────────────────────┐ │
14
+ │ │ a task and its signals │ │
15
+ │ └──────────────────────────┬─────────────────────────┘ │
16
+ └──────────────────────────────┼─────────────────────────────┘
17
+ v
18
+ ┌────────────┼───────────────────────────────────────────────┐
19
+ │ PROCESSING LAYER │
20
+ │ ┌────────────────────────────────────────────────────┐ │
21
+ │ │ match the worn laws │ │
22
+ │ └──────────────────────────┬─────────────────────────┘ │
23
+ └──────────────────────────────┼─────────────────────────────┘
24
+ v
25
+ ┌──────────────────────────────┼─────────────────────────────┐
26
+ │ OUTPUT LAYER v │
27
+ │ ┌────────────────────────────────────────────────────┐ │
28
+ │ │ one law, or none │ │
29
+ │ └────────────────────────────────────────────────────┘ │
30
+ └────────────────────────────────────────────────────────────┘
31
+ ```
32
+
33
+ The code is `src/memory-routing`. The worn package is `@0xray/repertoire` 0.2.9. Station is the wake ticket. This organ is the judgment. Do not pin 0.1.8.
34
+
35
+ stamped · 0xray 4.1.0
@@ -36,4 +36,4 @@ Logs become a report. A valid cache returns the formatted report and does not wr
36
36
  └────────────────────────────────────────────────────────────┘
37
37
  ```
38
38
 
39
- stamped · 0xray 4.0.42
39
+ stamped · 0xray 4.1.0
@@ -54,4 +54,4 @@ A state flow plate: one critic pass, one fix, one re-review, then stop.
54
54
 
55
55
  A FAIL names the file and a test that fails on the old code. One author fixes that hole. A second session waits while the verdict is open. Re-review that new head. A hole the new test did not lock returns to ONE FIX. A PASS ends the plate. A note stays a note and does not open another lap.
56
56
 
57
- stamped · 0xray 4.0.42
57
+ stamped · 0xray 4.1.0
@@ -59,4 +59,4 @@ Task text becomes an agent. `scoreAndRoute` scores the work, then `routeToAgent`
59
59
  └──────────────────────────────────────────────────────────────┘
60
60
  ```
61
61
 
62
- stamped · 0xray 4.0.42
62
+ stamped · 0xray 4.1.0
@@ -35,4 +35,4 @@ Today that file is `docs/inference/latest-session.json`. The home is `.xray/infe
35
35
 
36
36
  Station reads the file for heat. The inference accumulator reads `session-*.json` beside it. Do not mint a `session-<date>-<sha>` file for the station note.
37
37
 
38
- stamped · 0xray 4.0.42
38
+ stamped · 0xray 4.1.0
@@ -32,4 +32,4 @@ The published manual is docs-site/docs.
32
32
 
33
33
  Guides, architecture, and introduction live here. Factory notes under `docs/` are a different set. Reflections stay in `docs/reflections/`.
34
34
 
35
- stamped · 0xray 4.0.42
35
+ stamped · 0xray 4.1.0
@@ -32,4 +32,4 @@ A stamped plate is one drawing for one plane.
32
32
 
33
33
  The file is `docs-site/docs/plates/<id>.md`. Each opened segue gets its own plate. The hook does not author this file. The plate that belongs here is review.
34
34
 
35
- stamped · 0xray 4.0.42
35
+ stamped · 0xray 4.1.0
@@ -35,4 +35,4 @@ Read it after a compact. Leave Intent alone. The plan is the next cut. The long
35
35
  The station module writes this card. Heat adds `Cascade: record-map · notes N current`. The count is the current index. The body stays on the notes page.
36
36
 
37
37
  The card keeps the named plane. `Sleeve: on` means the previous ticket came back, the worn plate matched the package, the previous ticket matched the working record, and inspect passed. Judgement is continue, retry N, stop, or start. The same miss keeps its retry. A different ticket stops. Payments is on only when the ticket is a payment.
38
- stamped · 0xray 4.0.42
38
+ stamped · 0xray 4.1.0
@@ -32,4 +32,4 @@ On a compact event applyStationHeat stamps the notes pickup line.
32
32
 
33
33
  `isCompactHook` is true when the hook name contains compact. The body of NOTES.md is left alone. The plates that belong here are pickup-stamp and notes-page.
34
34
 
35
- stamped · 0xray 4.0.42
35
+ stamped · 0xray 4.1.0
@@ -35,4 +35,4 @@ Reporting reads the activity log and may write a report. Station reads `latest-s
35
35
 
36
36
  Repertoire already keeps `inference-state.json` and the day log under `.xray/state/repertoire/`. Goggles does not write these files. It reads a plate when one plane is named.
37
37
 
38
- stamped · 0xray 4.0.42
38
+ stamped · 0xray 4.1.0
@@ -32,4 +32,4 @@ Suit settings are features, config, and codex.
32
32
 
33
33
  There is no settings.json. The files are `.xray/features.json`, `.xray/config.json`, and `.xray/codex.json`. The package copies live under `xray/`.
34
34
 
35
- stamped · 0xray 4.0.42
35
+ stamped · 0xray 4.1.0
@@ -36,4 +36,4 @@ A worn project is a consumer. Its writes go to its own `.xray/logs` and `.xray/i
36
36
 
37
37
  A fresh wear fastens mill and inspect. Grok's Goggles launcher stays on that install: the checkout script when the package name is `0xray`, and `node_modules/0xray` for every other project.
38
38
 
39
- stamped · 0xray 4.0.42
39
+ stamped · 0xray 4.1.0
@@ -14,7 +14,7 @@ Give your agent a suit. The rules stay on, you add powers, and it runs in the to
14
14
  ├────────────────────────────────────────────────────────────┤
15
15
  │ · the rules stay on │
16
16
  │ · you put it on once │
17
- │ · it builds the factories │
17
+ │ · it builds the foundries │
18
18
  └────────────────────────────────────────────────────────────┘
19
19
  │
20
20
  you add powers
@@ -37,6 +37,6 @@ Give your agent a suit. The rules stay on, you add powers, and it runs in the to
37
37
  goggles views one plane
38
38
  ```
39
39
 
40
- Same rules in the repo. You are not locked into one app.
40
+ A foundry is mills and hangars. The mill builds and ships. The hangar is the shop. Same rules in the repo. You are not locked into one app.
41
41
 
42
- stamped · 0xray 4.0.42
42
+ stamped · 0xray 4.1.0
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: Synthesis
3
+ sidebar_label: Synthesis
4
+ ---
5
+
6
+ # Synthesis
7
+
8
+ The reflect checkpoint for this checkout.
9
+
10
+ ```
11
+ ┌────────────────────────────────────────────────────────────┐
12
+ │ INPUT LAYER │
13
+ │ ┌────────────────────────────────────────────────────┐ │
14
+ │ │ a gate, a turn, or a finished todo │ │
15
+ │ └──────────────────────────┬─────────────────────────┘ │
16
+ └──────────────────────────────┼─────────────────────────────┘
17
+ v
18
+ ┌────────────┼───────────────────────────────────────────────┐
19
+ │ PROCESSING LAYER │
20
+ │ ┌────────────────────────────────────────────────────┐ │
21
+ │ │ the checkpoint when enabled │ │
22
+ │ └──────────────────────────┬─────────────────────────┘ │
23
+ └──────────────────────────────┼─────────────────────────────┘
24
+ v
25
+ ┌──────────────────────────────┼─────────────────────────────┐
26
+ │ OUTPUT LAYER v │
27
+ │ ┌────────────────────────────────────────────────────┐ │
28
+ │ │ due or not due │ │
29
+ │ └────────────────────────────────────────────────────┘ │
30
+ └────────────────────────────────────────────────────────────┘
31
+ ```
32
+
33
+ The file is `src/nucleus/synthesis.ts`. The checkpoint is `.xray/state/synthesis-checkpoint.json`. While `synthesis.enabled` is false, a slice is not written and it does not come due.
34
+
35
+ stamped · 0xray 4.1.0
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: Temperament
3
+ sidebar_label: Temperament
4
+ ---
5
+
6
+ # Temperament
7
+
8
+ Ceremony scales by host.
9
+
10
+ ```
11
+ ┌────────────────────────────────────────────────────────────┐
12
+ │ INPUT LAYER │
13
+ │ ┌────────────────────────────────────────────────────┐ │
14
+ │ │ a host │ │
15
+ │ └──────────────────────────┬─────────────────────────┘ │
16
+ └──────────────────────────────┼─────────────────────────────┘
17
+ v
18
+ ┌────────────┼───────────────────────────────────────────────┐
19
+ │ PROCESSING LAYER │
20
+ │ ┌────────────────────────────────────────────────────┐ │
21
+ │ │ read suit_temperament │ │
22
+ │ └──────────────────────────┬─────────────────────────┘ │
23
+ └──────────────────────────────┼─────────────────────────────┘
24
+ v
25
+ ┌──────────────────────────────┼─────────────────────────────┐
26
+ │ OUTPUT LAYER v │
27
+ │ ┌────────────────────────────────────────────────────┐ │
28
+ │ │ frontier warns, guided denies │ │
29
+ │ └────────────────────────────────────────────────────┘ │
30
+ └────────────────────────────────────────────────────────────┘
31
+ ```
32
+
33
+ The module is `src/nucleus/suit-temperament.ts`. A missing `suit_temperament` stays guided. Frontier warns when a spawn has no plan. Guided and strict deny that spawn. Codex stays on. The guide is `docs-site/docs/guides/v3-temperament.md`.
34
+
35
+ stamped · 0xray 4.1.0
@@ -30,6 +30,6 @@ The suit writes its trail under .xray.
30
30
  └────────────────────────────────────────────────────────────┘
31
31
  ```
32
32
 
33
- Session boot, the lens match line, and the station card are state. The agent reads them. Do not commit `.xray/state`.
33
+ Session boot and the station card are state. `.xray/state/LENS.md` is the plane cards. A named plane whose Entry and Exit are missing is written there, and later passes read that card. Commit `.xray/state/LENS.md`. Do not commit the rest of `.xray/state`.
34
34
 
35
- stamped · 0xray 4.0.42
35
+ stamped · 0xray 4.1.0
@@ -32,4 +32,4 @@ Refresh writes one Fresh line from git and the published package.
32
32
 
33
33
  refreshFreshness in src/nucleus/work-freshness.mjs fetches origin, reads npm view 0xray version, and returns that one line. A compact hook does not call it. The plate that belongs here is station-card.
34
34
 
35
- stamped · 0xray 4.0.42
35
+ stamped · 0xray 4.1.0
@@ -35,4 +35,4 @@ The path table is `src/integrations/hooks/write-home.cjs`. Writers use it. Reade
35
35
 
36
36
  Still on the old path until each caller is rewired: the activity logger, the framework logger, the pipeline hook, the Grok hook, the Hermes bridge, station capture, `saveSessionInference`, reporting, pulse, monitor, and `features.json` `log_path`.
37
37
 
38
- stamped · 0xray 4.0.42
38
+ stamped · 0xray 4.1.0
package/llms.txt CHANGED
@@ -1,21 +1,25 @@
1
1
  # 0xray
2
2
 
3
- > Exo for coding agents. A suit that survives the context window. Not a catalog of 45 skills.
3
+ > A three-subsystem autonomous engine. The suit is the wear. The next session wakes with the job.
4
4
 
5
- **4.0** — mill+inspect plant, 7 MCPs, Codex 69. Constitution always on.
5
+ **4.1** — mill+inspect plant, 7 MCPs, Codex 69. Constitution always on.
6
6
 
7
7
  Confer votes. Burst runs the swarm.
8
8
 
9
+ **4.1** — a suit that survives the context window
10
+
11
+ 0xRay is a three-subsystem autonomous engine. The suit is the wear. Inference remembers. External Governance judges. The Autonomous Engine runs the work. The host you already run wears it: Grok, OpenCode, Hermes, OpenClaw, or Cursor. Memory, judgement, and payments come on with the suit. When the window closes, the next session wakes with the job, the page, and the laws. Confer votes: the agents on a decision vote, and only a real yes carries the work. Burst runs the swarm, so the agents are in the work as it happens. A foundry is built from mills and hangars.
12
+
9
13
  Default consumer wear is **mill plant** (`mill` + `inspect`), not a 45-skill / 42-agent costume dump. `foundry.json` `"costume": true` is the opt-in dump. Do not use costume to land hangar shops. Fasten is **foundry-plant/0**: builtin plant is mill+inspect only. `foundry.json` `"plant": "@0xray/blip"` (aliases `"plant": "blip"` / `"plant": "sound"`) fastens whatever that mill package declares. Organs (looker, vibe, mixer) live in the mill — adding an organ is a mill publish, not an xray catalog PR. CLI shims `foundry blip|sound` still exist on foundry 0.1.11+; fasten is the new cut. Inspect reports the last bed or blip receipt the mill exported. Nested mill `@0xray/foundry` 0.1.12. Not costume.
10
14
 
11
15
  ## Wear (what a stranger gets)
12
16
 
13
- - `npm install 0xray` — postinstall fastens mill+inspect, writes 7 MCP `.mcp.json`, four host bridges (OpenCode, Grok, Hermes, OpenClaw) plus Cursor `.cursor/hooks.json`, overlays their plant. Grok last-mile dest is project `.grok/plugins/0xray`. Shared HOME does not last-wins clobber machine `~/.grok/plugins/0xray`. Isolated HOME must not write the machine plugin. Does **not** write consumer-root `SKILLS.md`. Lead cadence: `grok-bot/OP-PROC.md` (team specifics live in `house/`) — a peer continues from Station + Repertoire; dummy tests `SKILLS.md`; same-sess wear; branch/PR; OTP then poll; loop until Station; live ticks, not idle pacers.
17
+ - `npm install 0xray` links vendored `@0xray/repertoire` and prints `npx 0xray wear`. It does not write `.mcp.json` or the chat bridges. `npx 0xray wear` writes the consumer suit: managed `AGENTS.md`, `.xray` config, seven MCP servers, and the OpenCode, Grok, Hermes, and OpenClaw bridges. Inside a git checkout, wear also fastens Cursor project hooks. Grok last-mile dest is project `.grok/plugins/0xray`. Shared HOME does not last-wins clobber machine `~/.grok/plugins/0xray`. Isolated HOME must not write the machine plugin. Does **not** write consumer-root `SKILLS.md`. Lead cadence: `grok-bot/OP-PROC.md` (team specifics live in `house/`) — a peer continues from Station + Repertoire; dummy tests `SKILLS.md`; same-sess wear; branch/PR; OTP then poll; loop until Station; live ticks, not idle pacers.
14
18
  - Memory scoring rules: [docs/memory-scoring.md](docs/memory-scoring.md). The orchestrator links that file. It does not copy the rules.
15
19
  - Host `preCompact` writes the hook line and per-session receipt on the suit mill and on nested consumer wear roots (a bench with local `node_modules/0xray`). A counted cut needs a non-empty generation id and a numeric usage percent.
16
20
  - `@0xray/grok-bot`: the general page is `grok-bot/OP-PROC.md`. The team overlay is `house/` and is not in that npm pack. `templates/house/` ships. `grok-bot house init` copies the template and refuses to overwrite. Doctor uses `GROK_BOT_HOUSE` when set, otherwise walks up from the working directory for `house/HOUSE.md`.
17
21
  - MCP servers start through `scripts/node/mcp-launch.cjs`. They see PATH, HOME, and XRAY_ROOT, plus the names on their keep list. Tokens such as NPM_TOKEN are not inherited. User env values stay out of argv. Postinstall keeps user edits to AGENTS.md, `.mcp.json`, and `opencode.json`. `house init` does not copy EXAMPLE.md. Doctor FAILs while `house/EXAMPLE.md` exists. Inspect has a machinePlugin check. The Cursor hook defaults XRAY_ROOT to the suit directory.
18
- - `npm install` only creates the relative `node_modules/@0xray/repertoire` link to the vendored repertoire and prints `npx 0xray wear`. Run `npx 0xray wear` after install; it writes only the consumer project's `.cursor/hooks.json`. `npx 0xray unwear` restores the pre-wear snapshot.
22
+ - `npx 0xray unwear` restores the pre-wear snapshot. Outside a git checkout, wear still writes the suit and skips only the Cursor hooks, with one warning.
19
23
  - 4.0.30: `npx 0xray wear` and `setup` also work outside a git checkout. They write the 4.0.28 project setup and skip only Cursor hooks, with one warning. In a git checkout they write the 4.0.28 project setup plus Cursor hooks.
20
24
 
21
25
  - `npx @0xray/foundry mint --skip-live` — re-fasten mill plant, then inspect.
@@ -43,7 +47,7 @@ Registered in `.mcp.json` as `npx -y 0xray mcp <cmd>`:
43
47
  | `xray-code-review` | Proposal quality |
44
48
  | `xray-architect-tools` | System design |
45
49
 
46
- Not an 8th `xray-*` server. **Repertoire is preferred** — vendored 0.2.9 ships on (`npx @0xray/repertoire mcp`). Dest is named laws, not hangar `repo-*` or git slugs. Survive compact is **Station** (Read `.xray/state/STATION.md`). Station is the ticket, not a substitute for Repertoire. Do not pin 0.1.8.
50
+ Not an 8th `xray-*` server. **Repertoire is preferred** — vendored 0.2.9 ships on (`npx @0xray/repertoire mcp`). Dest is named laws, not hangar `repo-*` or git slugs. The wake ticket is **Station** (Read `.xray/state/STATION.md`). Station is the ticket, not a substitute for Repertoire. Do not pin 0.1.8.
47
51
 
48
52
  ## Codex 69 (always on)
49
53
 
@@ -58,10 +62,14 @@ Not an 8th `xray-*` server. **Repertoire is preferred** — vendored 0.2.9 ships
58
62
  - **Hangar** — plants factory shops on the four floors. Coexists with mill plant via shop plant allowlist.
59
63
  - **42 YML / 45 SKILL.md** — exo catalog in this repo. Not default consumer wear.
60
64
 
65
+ ## Live board (Bifrost)
66
+
67
+ The board seats see is the collector board. `house/live/feed/live_mesh.py` runs the collector and the board every `LIVE_WATCH_S` seconds (default 45). A cloud agent is a board row (`bcId`, owning seat, linked card, state `running`, `finished`, or `failed`). `live-inbox` requires `LIVE_URL`, `SEAT_KEYS_DIR`, and `LIVE_CURSORS`, and exits 2 when one is missing. The seat wake is `grok-bot/templates/house/fleet/WAKE-ROUTINE.md`: turn start on every turn, turn end on every exit. A stuck card sends L1 to the next owner or the card owner, and L2 to the CoS role. Plate: `docs-site/docs/plates/bifrost.md`. Lexicon: `grok-bot/LEXICON.md`, including **button up**.
68
+
61
69
  ## Docs
62
70
 
63
71
  - [README.md](README.md) — exo landing
64
- - [AGENTS.md](AGENTS.md) — framework card
72
+ - [AGENTS.md](AGENTS.md) — suit card
65
73
  - [AGENTS-consumer.md](AGENTS-consumer.md) — consumer card (copied to `AGENTS.md` on install)
66
74
  - [SKILLS.md](SKILLS.md) — catalog (costume / self-plant, not default sync)
67
75
  - [Foundry](docs-site/docs/architecture/v4-foundry.md) — mill vs exo, foundry-plant/0, shopPlant
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.42",
4
- "description": "Multi-agent orchestration and Codex governance for OpenCode, Hermes, Grok Build, and OpenClaw",
3
+ "version": "4.1.1",
4
+ "description": "Three-subsystem autonomous engine. The suit powers the agent you already run: memory, judgement, payments, and the wake.",
5
5
  "readme": "README.md",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -80,7 +80,7 @@
80
80
  "test:code-analysis": "npm test -- src/__tests__/unit/codebase-context-analyzer.test.ts src/__tests__/unit/dependency-graph-builder.test.ts src/__tests__/unit/rule-enforcer.test.ts src/__tests__/unit/codex-parser.test.ts src/__tests__/unit/codex-injector.test.ts",
81
81
  "test:processors": "npm test -- src/__tests__/unit/processor-activation.test.ts src/__tests__/unit/typescript-compilation-processor.test.ts",
82
82
  "test:miscellaneous": "npm test -- src/__tests__/unit/blocked-test.test.ts",
83
- "test:grok-bot": "npm test -- src/__tests__/unit/grok-bot-seat-doctor.test.ts src/__tests__/unit/grok-bot-op-proc-map.test.ts src/__tests__/unit/lead-cadence.test.ts src/__tests__/unit/grok-bot-auto-review-policy.test.ts",
83
+ "test:grok-bot": "npm test -- src/__tests__/unit/grok-bot-seat-doctor.test.ts src/__tests__/unit/grok-bot-house-migrate.test.ts src/__tests__/unit/grok-bot-house-template.test.ts src/__tests__/unit/grok-bot-op-proc-map.test.ts src/__tests__/unit/lead-cadence.test.ts src/__tests__/unit/grok-bot-auto-review-policy.test.ts",
84
84
  "test:quick": "npm test -- src/__tests__/integration/boot-orchestrator.integration.test.ts src/__tests__/unit/config-loader.test.ts src/__tests__/unit/state-manager.test.ts",
85
85
  "test:comprehensive": "npm run typecheck && npm run test:unit && npm run test:core-framework && npm run test:security && npm run test:performance && npm run test:session-management && npm run test:code-analysis && npm run test:processors && npm run test:miscellaneous && npm test -- src/__tests__/unit/llm-governance-provider.test.ts src/__tests__/unit/mcp-server-smoke.test.ts src/__tests__/unit/cursor-hooks.test.ts src/__tests__/unit/host-vs-mill-score.test.ts src/__tests__/unit/wear-pack-file-list.test.ts && npm run test:grok-bot",
86
86
  "test:integration-all": "npm test -- src/__tests__/integration/",
@@ -17,7 +17,7 @@ npx @0xray/foundry reconcile [patch|minor|major] [--apply] [--check]
17
17
  npx @0xray/foundry stamp
18
18
  npx @0xray/foundry docs-check
19
19
  npx @0xray/foundry docs-build
20
- npx @0xray/foundry gate [--verify-only]
20
+ npx @0xray/foundry gate [--verify-only|--prove-published]
21
21
  npx @0xray/foundry release [patch|minor|major] --dry-run
22
22
  npx @0xray/foundry release [patch|minor|major] --i-mean-it
23
23
  npx @0xray/foundry release --publish-only --dry-run
@@ -37,9 +37,11 @@ npx @0xray/foundry hooks
37
37
 
38
38
  `release` without `--dry-run` requires `--i-mean-it` or `FOUNDRY_RELEASE=1`. It is a bump/commit/push/publish bot for the **milled cwd**, not a casual command.
39
39
 
40
+ On the 0xray repo, `reconcile --apply` and `stamp` refuse unless `release.mjs` called them. `npm run version:sync` refuses here too. Run `npx @0xray/foundry release [patch|minor|major] --i-mean-it`. That command publishes. A docs fix does not.
41
+
40
42
  `FOUNDRY_ROOT` overrides cwd (the repo being milled).
41
43
 
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.
44
+ `gate` is build + test + docs-check. `--skip-docs` fails the gate. `--prove-published` is Gate D and does not publish: npm lists the version, the annotated tag points at HEAD, and the GitHub Release page exists. A local gate pass is not Gate D. `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
45
 
44
46
  `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
47
 
@@ -60,7 +62,7 @@ After mill plant is fastened, overlay their plant (defaults; remap in `foundry.j
60
62
 
61
63
  **Mill-fill is law:** their keys/files win; mill names they did not plant stay unless they overlay the same name. JSON facets always merge. Skill overlay is project dirs on every TUI floor (OpenCode, Grok, Hermes, OpenClaw). YML agents stay OpenCode. CLI re-wear calls mint **once** after mill copies. Isolated HOME is passwd home, not `os.homedir()`. CI report is `.xray/foundry-ci-report.json` (`.opencode/logs` shim).
62
64
 
63
- **Default mill plant:** `mill` + `inspect` (inspect AI work). Fasten is **foundry-plant/0**: builtin plant is mill+inspect only (files from this package `plant/`). Fastens a suit, not an empty one. Not 45/42 costume. `foundry.json` `"costume": true` copies that dump. **Repertoire is preferred** (vendored, dest = laws). PPE stays worn.
65
+ **Default mill plant:** `mill` + `inspect` (inspect AI work). Fasten is **foundry-plant/0**: builtin plant is mill+inspect only (files from this package `plant/`). Fastens a suit, not an empty one. The mill suit also wears every catalog skill and every role file. A blip or sound seat fastens that plant only. A name outside the fastened set still fails inspect. **Repertoire is preferred** (vendored, dest = laws). PPE stays worn.
64
66
 
65
67
  **foundry-plant/0:** `foundry.json` `"plant": "@0xray/blip"` (aliases `"plant": "blip"` / `"plant": "sound"`) fastens whatever that mill package declares and ships in its own `plant/`. Organs (looker, vibe, mixer) live in the mill. Adding an organ is a mill publish, not a foundry catalog PR. CLI shims `foundry blip|sound` still exist on foundry 0.1.11+; fasten is the new cut. Foundry **0.1.12**.
66
68
 
@@ -114,12 +114,91 @@ function loadFoundryParams(targetDir) {
114
114
  return params;
115
115
  }
116
116
 
117
- /** 45/42 costume dump. Default false on consumers. Exo mill keeps the costume. */
117
+ /** Exo repo, or foundry.json costume true. This flag does not gate catalog skills. */
118
118
  function wantsCostume(targetDir) {
119
119
  if (isExoRepo(targetDir)) return true;
120
120
  return loadFoundryExtra(targetDir).costume === true;
121
121
  }
122
122
 
123
+ function suitPackageRoot(start) {
124
+ let dir = start;
125
+ for (let i = 0; i < 4 && dir; i += 1) {
126
+ if (
127
+ fs.existsSync(path.join(dir, "src", "skills"))
128
+ || fs.existsSync(path.join(dir, "dist", "skills"))
129
+ || fs.existsSync(path.join(dir, "src", "opencode", "agents"))
130
+ ) return dir;
131
+ const parent = path.dirname(dir);
132
+ if (parent === dir) break;
133
+ dir = parent;
134
+ }
135
+ return start || "";
136
+ }
137
+
138
+ function catalogSkillDir(packageRoot) {
139
+ const base = suitPackageRoot(packageRoot);
140
+ const dirs = [path.join(base, "dist", "skills"), path.join(base, "src", "skills")];
141
+ return dirs.find((dir) => listSkillNamesAt(dir).length > 0) || "";
142
+ }
143
+
144
+ function catalogSkillNames(packageRoot) {
145
+ const dir = catalogSkillDir(packageRoot);
146
+ return dir ? listSkillNamesAt(dir) : [];
147
+ }
148
+
149
+ function catalogAgentDirs(packageRoot) {
150
+ const base = suitPackageRoot(packageRoot);
151
+ return [
152
+ path.join(base, "src", "opencode", "agents"),
153
+ path.join(base, ".opencode", "agents"),
154
+ ].filter((p) => fs.existsSync(p));
155
+ }
156
+
157
+ function catalogAgentFiles(packageRoot) {
158
+ const names = new Set();
159
+ for (const dir of catalogAgentDirs(packageRoot)) {
160
+ for (const file of listAgentFilesAt(dir)) names.add(file);
161
+ }
162
+ return [...names];
163
+ }
164
+
165
+ /**
166
+ * The mill suit wears the catalog. A blip-only or sound-only seat does not.
167
+ * Costume stays a separate flag and does not decide this.
168
+ */
169
+ function suitCatalogApplies(targetDir, millPlant, packageRoot) {
170
+ const fromPlant = Array.isArray(millPlant?.kinds) ? millPlant.kinds : [];
171
+ const kinds = fromPlant.length > 0
172
+ ? fromPlant
173
+ : loadFactoryPlantKinds(targetDir, packageRoot || "");
174
+ return kinds.includes("mill");
175
+ }
176
+
177
+ /** Every catalog skill and role file. An existing file stays. */
178
+ function wearCatalog(packageRoot, targetDir) {
179
+ const source = catalogSkillDir(packageRoot);
180
+ if (source) {
181
+ for (const dir of listProjectSkillDirs(targetDir)) {
182
+ for (const name of catalogSkillNames(packageRoot)) {
183
+ const src = path.join(source, name, "SKILL.md");
184
+ const dest = path.join(dir, name, "SKILL.md");
185
+ if (!fs.existsSync(src) || fs.existsSync(dest)) continue;
186
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
187
+ fs.copyFileSync(src, dest);
188
+ }
189
+ }
190
+ }
191
+ const agentsDest = path.join(targetDir, ".opencode", "agents");
192
+ for (const dir of catalogAgentDirs(packageRoot)) {
193
+ for (const file of listAgentFilesAt(dir)) {
194
+ const dest = path.join(agentsDest, file);
195
+ if (fs.existsSync(dest)) continue;
196
+ fs.mkdirSync(agentsDest, { recursive: true });
197
+ fs.copyFileSync(path.join(dir, file), dest);
198
+ }
199
+ }
200
+ }
201
+
123
202
  function millPlantDir(millPackageRoot) {
124
203
  return millPlantProtocol.foundryPlantDir(millPackageRoot);
125
204
  }
@@ -208,11 +287,21 @@ function inventoryPlantKinds(inventory) {
208
287
  return millPlantProtocol.plantKindsFromInventory(inventory);
209
288
  }
210
289
 
290
+ function skillDirEntry(parent, entry) {
291
+ if (entry.isDirectory()) return true;
292
+ if (!entry.isSymbolicLink()) return false;
293
+ try {
294
+ return fs.statSync(path.join(parent, entry.name)).isDirectory();
295
+ } catch {
296
+ return false;
297
+ }
298
+ }
299
+
211
300
  function listSkillNamesAt(skillsSrc) {
212
301
  if (!isDirectory(skillsSrc)) return [];
213
302
  const names = [];
214
303
  for (const entry of fs.readdirSync(skillsSrc, { withFileTypes: true })) {
215
- if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
304
+ if (entry.name.startsWith(".") || !skillDirEntry(skillsSrc, entry)) continue;
216
305
  const skillMd = path.join(skillsSrc, entry.name, "SKILL.md");
217
306
  if (!fs.existsSync(skillMd)) continue;
218
307
  names.push(entry.name);
@@ -615,7 +704,10 @@ function costumeDumpExtras(targetDir, millPlant, tree) {
615
704
  if (Array.isArray(spec?.agents)) plantMapAgents.push(...spec.agents);
616
705
  }
617
706
  }
707
+ const packageRoot = tree?.millPackageRoot || "";
708
+ const catalogOn = suitCatalogApplies(targetDir, millPlant, packageRoot);
618
709
  const allowedSkills = new Set([
710
+ ...(catalogOn ? catalogSkillNames(packageRoot) : []),
619
711
  ...(Array.isArray(millPlant?.skills) ? millPlant.skills : []),
620
712
  ...(Array.isArray(millPlant?.sound?.skills) ? millPlant.sound.skills : []),
621
713
  ...(Array.isArray(millPlant?.blip?.skills) ? millPlant.blip.skills : []),
@@ -627,6 +719,7 @@ function costumeDumpExtras(targetDir, millPlant, tree) {
627
719
  ...shopPlant,
628
720
  ]);
629
721
  const allowedAgents = new Set([
722
+ ...(catalogOn ? catalogAgentFiles(packageRoot) : []),
630
723
  ...(Array.isArray(millPlant?.agents) ? millPlant.agents : []),
631
724
  ...(Array.isArray(millPlant?.sound?.agents) ? millPlant.sound.agents : []),
632
725
  ...(Array.isArray(millPlant?.blip?.agents) ? millPlant.blip.agents : []),
@@ -795,12 +888,34 @@ function mintConsumerFromSsot(packageRoot, targetDir, log, tree) {
795
888
  return withDna;
796
889
  }
797
890
 
891
+
892
+ function gogglesDisabled(targetDir) {
893
+ const file = path.join(targetDir, ".xray", "features.json");
894
+ if (!fs.existsSync(file)) return false;
895
+ try {
896
+ const data = JSON.parse(fs.readFileSync(file, "utf8"));
897
+ return Boolean(data && data.goggles && data.goggles.enabled === false);
898
+ } catch {
899
+ return false;
900
+ }
901
+ }
902
+
903
+ function assertGogglesOn(targetDir) {
904
+ if (gogglesDisabled(targetDir)) {
905
+ throw new Error("goggles off — the suit keeps goggles on");
906
+ }
907
+ }
908
+
798
909
  function mintConsumerSuit(millPackageRoot, targetDir, log) {
910
+ assertGogglesOn(targetDir);
799
911
  if (isDogfood(millPackageRoot, targetDir)) {
800
912
  return { suit: "dogfood", skipped: true };
801
913
  }
802
914
  const params = loadFoundryParams(targetDir);
803
915
  const millPlant = fastenMillPlant(millPackageRoot, targetDir, log);
916
+ if (suitCatalogApplies(targetDir, millPlant, millPackageRoot)) {
917
+ wearCatalog(millPackageRoot, targetDir);
918
+ }
804
919
  const tree = overlayConsumerTree(targetDir, log, params);
805
920
  tree.plantKinds = millPlant.kinds || loadFactoryPlantKinds(targetDir);
806
921
  tree.millPlantSkills = millPlant.skills;
@@ -825,6 +940,7 @@ function mintConsumerSuit(millPackageRoot, targetDir, log) {
825
940
  resolveInside(targetDir, params.features),
826
941
  path.join(targetDir, ".xray", "features.json"),
827
942
  );
943
+ assertGogglesOn(targetDir);
828
944
  tree.config = overlayJsonFacet(
829
945
  resolveInside(targetDir, params.config),
830
946
  path.join(targetDir, ".xray", "config.json"),
@@ -866,6 +982,7 @@ module.exports = {
866
982
  loadShopPlant,
867
983
  declaredShopPlant,
868
984
  wantsCostume,
985
+ suitCatalogApplies,
869
986
  millPlantDir,
870
987
  loadFactoryPlantKinds,
871
988
  factoryPlantAllowlist,
@@ -884,6 +1001,7 @@ module.exports = {
884
1001
  listProjectSkillDirs,
885
1002
  mintConsumerFromSsot,
886
1003
  mintConsumerSuit,
1004
+ assertGogglesOn,
887
1005
  attachInventoryDna,
888
1006
  inventoryDna,
889
1007
  isDogfood,
@@ -13,7 +13,7 @@ The mill **fastens** a suit. Default mill plant is **inspect** (inspecting AI wo
13
13
 
14
14
  **Factory:** **Repertoire is preferred** (vendored 0.2.9 ships on; dest = named laws). Seven generated MCP. Constitution (PPE) stays worn. Not a fifth MCP. Not 5.0.
15
15
 
16
- **Costume:** `foundry.json` `"costume": true` copies the 45/42 mill costume.
16
+ **Skills:** the mill suit wears every catalog skill and every role file. The mill plant stays `mill` and `inspect`. A blip or sound seat fastens that plant only.
17
17
 
18
18
  ```bash
19
19
  npx @0xray/foundry mint
@@ -20,7 +20,7 @@ import { execSync } from "child_process";
20
20
  import fs from "fs";
21
21
  import path from "path";
22
22
  import { fileURLToPath } from "url";
23
- import { readRootPackage, resolveMillRoot } from "./mill-root.mjs";
23
+ import { isXrayExoRepo, readRootPackage, resolveMillRoot } from "./mill-root.mjs";
24
24
  import { packageLockVersions, syncPackageLockVersion } from "./version-manager.mjs";
25
25
 
26
26
  const rootDir = resolveMillRoot();
@@ -103,7 +103,7 @@ function fail(msg) {
103
103
  */
104
104
  export function publishedVersionCheckError(local, npmVersion) {
105
105
  if (compare(local, npmVersion) < 0) {
106
- return `package.json (${local}) must be >= npm (${npmVersion}). Run: npx @0xray/foundry reconcile patch --apply`;
106
+ return `package.json (${local}) must be >= npm (${npmVersion}). The bump is npx @0xray/foundry release patch --i-mean-it. That command publishes. A docs fix does not. Stop.`;
107
107
  }
108
108
  return null;
109
109
  }
@@ -134,6 +134,13 @@ function main() {
134
134
  }
135
135
 
136
136
  if (applyMode && bumpType) {
137
+ if (isXrayExoRepo(rootDir) && process.env.FOUNDRY_VIA_RELEASE !== "1") {
138
+ fail(
139
+ "This repo bumps only through scripts/foundry/release.mjs.\n" +
140
+ "Ship: node scripts/foundry/release.mjs patch --i-mean-it\n" +
141
+ "That command publishes. A docs fix does not. Stop.",
142
+ );
143
+ }
137
144
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
138
145
  pkg.version = target;
139
146
  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
@@ -167,7 +174,7 @@ function main() {
167
174
  const lockNow = packageLockVersions(rootDir);
168
175
  if (lockNow && (lockNow.root !== pkgVersion || lockNow.pkg !== pkgVersion)) {
169
176
  fail(
170
- `package-lock.json (${lockNow.root} / ${lockNow.pkg}) must match package.json (${pkgVersion}). The bumper writes both: npx @0xray/foundry reconcile patch --apply`,
177
+ `package-lock.json (${lockNow.root} / ${lockNow.pkg}) must match package.json (${pkgVersion}). The bumper is npx @0xray/foundry release patch --i-mean-it. That command publishes. A docs fix does not. Stop.`,
171
178
  );
172
179
  }
173
180