@xmarts/genius-setup 1.11.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmarts/genius-setup",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"description": "One-command, self-updating onboarding for Xmarts Genius (Brain MCP + per-turn injection + automatic session/time capture + presence heartbeat for honest time-tracking 'amarre' + plan/committee→Brain enforcement + CLAUDE.md protocol + MCP fan-out: provisions the consultant's granted MCP servers into Claude Code & Claude Desktop). Secret-free onboarding via single-use setup-token exchange. Installs once; self-updates daily so new tools/skills/features arrive with zero action.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"genius-setup": "bin/genius-setup.js"
|
|
@@ -67,6 +67,7 @@ argument shape or hit an edge case.
|
|
|
67
67
|
| Deploy / install / upgrade a **module** | `manage_module`, `deploy_module` | ✅ — see [manage-client-modules.md](references/manage-client-modules.md) |
|
|
68
68
|
| Inspect a model's schema | `get_model_schema`, `list_models` | ✅ |
|
|
69
69
|
| Read / search a client's source code | `code_read`, `code_search`, `search_webapp_code` | ✅ |
|
|
70
|
+
| Give a **consultant a UI login** on a client | `execute_orm` (create `res.users`) | ✅ — see [provision-consultant-ui-access.md](references/provision-consultant-ui-access.md) |
|
|
70
71
|
| Snapshot / restore / export the DB | `create_snapshot`, `restore_snapshot`, `export_database` | ✅ |
|
|
71
72
|
| Restart Odoo | `trigger_restart` | ✅ |
|
|
72
73
|
| Build a chart/dashboard | `create_echart` | ✅ *(same infra caveat as webapps)* |
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Provisioning a consultant a UI login on a client Odoo
|
|
2
|
+
|
|
3
|
+
**The need (recurring):** a Genius consultant must log into a *client's* Odoo **UI**
|
|
4
|
+
(`https://<client>/web/login`) to work visually — test screens, configure Studio, click
|
|
5
|
+
through flows. Genius manages consultants centrally (`xma.consultant` on the master), but
|
|
6
|
+
each client is a **separate Odoo database**; a master identity is **not** a login on the
|
|
7
|
+
client. There is no SSO federation — the `xma_connect` gateway is HMAC machine-to-machine,
|
|
8
|
+
not user identity. So the consultant needs a real `res.users` **in that client instance**.
|
|
9
|
+
|
|
10
|
+
**Do NOT share the gateway service account** (`xma_genius@<client>`) or any other shared
|
|
11
|
+
login. It has only `base.group_user` (headless), sharing a password kills the audit trail,
|
|
12
|
+
and a plaintext password in a Claude session can be indexed by the Brain. Give each
|
|
13
|
+
consultant their **own** audited user.
|
|
14
|
+
|
|
15
|
+
## The pattern (scalable, sustainable, auditable)
|
|
16
|
+
|
|
17
|
+
**Per-consultant internal user in the client instance, provisioned on demand through the
|
|
18
|
+
Genius gateway, cloning an existing consultant's group profile, with a temp password the
|
|
19
|
+
consultant changes on first login.**
|
|
20
|
+
|
|
21
|
+
- **Auditable** — real per-person `res.users`; `create_uid`/`create_date`/login identify who.
|
|
22
|
+
- **Consistent** — clone the groups of a consultant who already works that client (no
|
|
23
|
+
over/under-grant guesswork). If none exists, use the client's Sales-user baseline
|
|
24
|
+
(`base.group_user` + the Sales "All Documents" group).
|
|
25
|
+
- **Central + repeatable** — one `execute_orm` through `target_client`; no per-client manual admin.
|
|
26
|
+
- **Least-shared-secret** — temp password, changed on first login; deep "modify anything"
|
|
27
|
+
work happens through the consultant's Claude Code + gateway (full ORM/code), NOT the UI login.
|
|
28
|
+
|
|
29
|
+
### UI login ≠ programmatic access — two distinct rails
|
|
30
|
+
1. **UI login** (this doc) — for *visual* work. Modest groups (mirror an existing consultant).
|
|
31
|
+
2. **Programmatic** (Claude Code + `beesmart_genius` MCP + `target_client`) — for reading
|
|
32
|
+
code, editing modules/webapps, running ORM. This already runs with full gateway access, so
|
|
33
|
+
a consultant rarely needs broad UI groups. Grant the UI the minimum for visual work; escalate
|
|
34
|
+
one group at a time only when a specific task in the UI is blocked.
|
|
35
|
+
|
|
36
|
+
## Runbook (≈1 minute)
|
|
37
|
+
|
|
38
|
+
Resolve the client UUID with `genius_capability_map` (its payload lists every client), then:
|
|
39
|
+
|
|
40
|
+
**1. Probe the client:** confirm reachable, the consultant has no login yet, whether SMTP
|
|
41
|
+
exists (usually not → no email invite → temp password), and an existing consultant to clone.
|
|
42
|
+
```python
|
|
43
|
+
U = env['res.users'].sudo()
|
|
44
|
+
base_url = env['ir.config_parameter'].sudo().get_param('web.base.url')
|
|
45
|
+
internal = [{'id': u.id, 'login': u.login, 'name': u.name}
|
|
46
|
+
for u in U.search([('share','=',False),('active','=',True)])]
|
|
47
|
+
exists = U.search([('login','=','<consultant.email>')]).ids
|
|
48
|
+
result = {'base_url': base_url, 'internal': internal, 'already_there': exists}
|
|
49
|
+
```
|
|
50
|
+
Pick the `source` user to clone (an existing consultant on this client). Odoo 19 uses
|
|
51
|
+
`group_ids` (NOT `groups_id`) for direct groups on `res.users`.
|
|
52
|
+
|
|
53
|
+
**2. Create the user** (clone groups + server-side temp password; suppress the reset-email
|
|
54
|
+
attempt that fails with no SMTP):
|
|
55
|
+
```python
|
|
56
|
+
U = env['res.users'].sudo()
|
|
57
|
+
LOGIN = '<consultant.email>' # match their xmarts.com email for consistency
|
|
58
|
+
if U.search([('login','=',LOGIN)]):
|
|
59
|
+
result = {'status': 'exists'}
|
|
60
|
+
else:
|
|
61
|
+
env.cr.execute("SELECT replace(gen_random_uuid()::text,'-','')")
|
|
62
|
+
raw = env.cr.fetchone()[0]
|
|
63
|
+
pw = 'Xma-%s-%s-Ux!' % (raw[:6], raw[6:12]) # no spaces, meets complexity
|
|
64
|
+
src = U.browse(<source_uid>) # an existing consultant on this client
|
|
65
|
+
comp = src.company_id.id or env.company.id
|
|
66
|
+
user = U.with_context(no_reset_password=True, mail_create_nosubscribe=True).create({
|
|
67
|
+
'name': '<Consultant Name>', 'login': LOGIN, 'email': LOGIN, 'password': pw,
|
|
68
|
+
'company_id': comp, 'company_ids': [Command.set([comp])],
|
|
69
|
+
'group_ids': [Command.set(src.group_ids.ids)],
|
|
70
|
+
})
|
|
71
|
+
result = {'status':'created','uid':user.id,'password':pw,'groups':user.group_ids.ids}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**3. Verify** the hash persisted (login will work) — never read/expose the hash value:
|
|
75
|
+
```python
|
|
76
|
+
env.cr.execute("SELECT (password IS NOT NULL AND length(password)>20) FROM res_users WHERE id=<uid>")
|
|
77
|
+
result = {'password_ok': bool(env.cr.fetchone()[0])}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**4. Deliver securely.** URL (`<base_url>/web/login`) + login are non-secret → inline is fine.
|
|
81
|
+
The password is a secret: the session-capture hook redacts `password: <value>` (English
|
|
82
|
+
keyword + value) both client- and server-side, so present it in **that exact form** — the
|
|
83
|
+
owner sees it live, the Brain stores `[REDACTED]`. Also write it to `~/.genius/secrets/<client>_<consultant>_ui.txt`
|
|
84
|
+
(chmod 600) for reliable relay. **Mandate a change on first login** (Preferences → Account
|
|
85
|
+
Security) — that burns the transited temp value.
|
|
86
|
+
|
|
87
|
+
**5. Give them Claude Code too** (so they can modify anything programmatically): on the
|
|
88
|
+
master, `env['xma.consultant'].browse(<id>).write({'token_expiry_mode':'7d'})` then
|
|
89
|
+
`.action_generate_setup_package()`; read the newest `xma.consultant.setup.wizard` for that
|
|
90
|
+
consultant → its `npx_command`. They run it once in VSCode (Windows: PowerShell form). It
|
|
91
|
+
installs the MCP + hooks + skills and self-updates daily. Confirm the client is in their
|
|
92
|
+
`client_ids` so `target_client` routing works.
|
|
93
|
+
|
|
94
|
+
## Notes / gotchas
|
|
95
|
+
- **No `signup_token` in this estate** (auth_signup is partial on xmarts.net/clients) → the
|
|
96
|
+
reset-link flow is unreliable; use the temp-password path. (Brain: "signup_token roto".)
|
|
97
|
+
- **Odoo 19:** `res.users` direct groups = `group_ids`; `all_group_ids` is computed (implied).
|
|
98
|
+
- **Revoke** = archive the user on the client (`delete_record` → `active=False`), reversible.
|
|
99
|
+
- **Don't** grant `base.group_system` (Settings/admin) by default — escalate per task only.
|
|
100
|
+
- This is a per-`(consultant, client)` on-demand action, not an auto-hook: not every
|
|
101
|
+
consultant needs UI on every client.
|