SLOPSHOPPER

chaturi-comune

Toate conturile Claude logate pe același PC văd aceleași chat-uri Code din aplicația desktop.

newcommandtoastprocesstimer
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · chaturi-comune
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM › /chaturi-comune ⎿ chaturi-comune: Chat-uri comune: funcționează doar pe Windows, cu aplicația desktop Claude. ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts
README

Symbai pentru Claude Code

Acest repo e un plugin Claude Code care învață asistentul AI cum să lucreze cu platforma Symbai (sistem de management pentru restaurante și hoteluri). Conține:

  • skills/ — workflow-uri pas-cu-pas (configurarea completă a unui client nou — onboarding, importul datelor din Excel/CSV — pagina de import condusă prin extensia Chrome + verificare prin conexiune, configurare Portal Clienți, configurare Aplicație Staff/Symbai Staff, găsește o pagină, investighează o masă, adaugă un produs/rețetă, design pentru meniul fizic tipărit — ca un grafician, prin conexiune + vision, programează o postare, rapoarte & prețuri, trimite ticket de suport/sugestie către echipa Symbai).
  • knowledge/ — biblioteca completă de cunoștințe client-facing: un ghid pentru FIECARE modul Symbai (POS & sală, meniu & rețete, stocuri & furnizori, producție & trasabilitate, rezervări & evenimente, personal, rapoarte & P&L, finanțe & e-Factura, livrări & magazin online, marketing & website, echipamente & KDS, setări, AI în aplicație), plus referința pentru aplicațiile native Expo (expo-aplicatii-mobile.md: Symbai POS, Symbai Portal, Symbai Staff, branding, emulator Android, build, GP/Viva app2app, push). Plus referințele transversale de navigare și operare MCP — agent-operare-avansata.md (standardul „consultant + inginer + QA" pentru task-uri complexe), erp-manufacturing-benchmark.md (pattern-uri ERP/MES pentru producție: BoM, MPS, readiness, QC, capacitate), navigare-rapida.md (cheat-sheet compact intenție→URL), navigare.md (cum DUCI userul pe pagină), claude-code-mcp-operare.md (doctrina skill→knowledge→MCP live→dry-run→confirmare→verificare), harta-aplicatiei.md (indexul exhaustiv al paginilor) și tools-mcp.md (catalog generat din registry-ul live al tool-urilor MCP, cu modelul de permisiuni) — și folderul knowledge/onboarding/ (planul general + 12 faze pentru configurarea de la zero a unui client nou, folosit de skill-ul onboarding-symbai).

Pluginul se folosește împreună cu conexiunea MCP la instanța ta Symbai (date live + acțiuni reale). Conexiunea o adaugi separat din portalul Hub. Pentru email marketing, skill-urile sunt optimizate pentru flow-uri complexe, deliverability/warm-up, trimitere predictivă pe ore individuale și atribuire conversii din POS/rezervări.

Instalare (clientul rulează o singură dată)

Metoda recomandată — prin fișier, cu AUTO-UPDATE pornit din start. Funcționează în orice mediu (inclusiv aplicația desktop, unde comanda /plugin poate lipsi) și e singura care pornește actualizarea automată. Editează settings.json din folderul Claude (Windows: C:\Users\<nume>\.claude\settings.json; macOS/Linux: ~/.claude/settings.json; creează-l dacă lipsește) și îmbină următoarele chei, păstrând restul fișierului:

{
  "extraKnownMarketplaces": {
    "symbai": {
      "source": { "source": "git", "url": "https://github.com/sinesteziadrimo/symbaimemory.git" },
      "autoUpdate": true
    }
  },
  "enabledPlugins": { "symbai-core@symbai": true }
}

⚠️ "autoUpdate": true este obligatoriu — fără el rămâi blocat pe versiunea de la instalare și nu mai primești ghidurile noi. Comanda /plugin marketplace add nu pornește auto-update — de aceea folosim fișierul.

Începând cu symbai-core v0.27, pluginul pornește la fiecare sesiune un hook fail-safe de self-update: aduce clona locală de marketplace symbai la zi (fast-forward; re-sincronizare cu upstream dacă a divergat dar nu are modificări locale) și, dacă a apărut o versiune nouă, face singur upgrade-ul instalării — versiunea nouă se încarcă la următoarea pornire. E necesar pentru că auto-update-ul nativ al pluginurilor nu rulează în aplicația desktop (procesul e pornit cu DISABLE_AUTOUPDATER=1); hook-ul nu depinde de el și nu cere pași manuali clientului.

Apoi instalează pluginul o singură dată (activarea efectivă), pe metoda disponibilă la tine:

# caseta de chat Claude Code:
/plugin install symbai-core@symbai
# aplicația desktop fără /plugin: Customize / Settings → Plugins/Marketplaces → instalează „symbai-core" din marketplace-ul „symbai"
# terminal, doar dacă `claude --version` merge:
claude plugin install symbai-core@symbai

Repornește Claude Code. De aici încolo pluginul se actualizează singur la fiecare pornire — nu mai faci nimic.

Separat, din portalul tău Symbai Hub → Acces AI, ia instrucțiunile de conectare la datele instanței tale (server MCP symbai). Dacă ceva nu merge la conectare, spune-i asistentului „conectează-mă la Symbai" — skill-ul conecteaza-symbai îl ghidează (inclusiv la eroarea „Some MCP servers could not be loaded").

Actualizare

De la symbai-core v0.27 nu trebuie să faci nimic — hook-ul de self-update din plugin aduce marketplace-ul la zi și upgradează pluginul la fiecare pornire de sesiune (cu un throttle de 6h), independent de auto-update-ul nativ al Claude Code (care în aplicația desktop nici nu rulează). "autoUpdate": true din settings rămâne recomandat ca plasă suplimentară pe CLI.

Dacă ești blocat pe o versiune veche (≤0.26.x, dinainte de self-update) sau vrei ultima versiune imediat: scrie în chat „actualizează skill-urile Symbai" (skill-ul symbai-update conține pașii de recovery — un git merge --ff-only pe clona de marketplace + rularea scriptului self-heal-marketplace.mjs --force), sau, dacă ai comanda disponibilă, /plugin marketplace update symbai. După o singură astfel de trecere pe v0.27+, actualizarea rămâne automată pe veci.

Cum se livrează conținut nou

Echipa Symbai urcă fișiere noi de skill/knowledge în acest repo (pe main) și bumpează versiunea în plugins/symbai-core/.claude-plugin/plugin.json, plugins/symbai-core/.codex-plugin/plugin.json și intrarea din .claude-plugin/marketplace.json. Clienții cu autoUpdate: true le primesc automat la următoarea pornire; ceilalți, manual cu /plugin marketplace update symbai.

Bumpul de versiune e obligatoriu la fiecare livrare. Claude Code servește pluginul dintr-un folder fixat pe versiune (cache/symbai/symbai-core/<versiune>/); dacă version nu se schimbă, clienții rămân pe copia veche din cache chiar dacă au tras commit-uri noi.

Mod-uri Claude Code: pornire și retragere din marketplace.json

Câmpul category al unei intrări din .claude-plugin/marketplace.json îi spune lui Symbai Connect ce să facă cu pluginul pe PC-urile clienților. Ajunge la ei doar cu un pachet nou: numărul pachetului e versiunea symbai-core, deci se bumpează și ea, apoi build-package.ps1 -Publish.

categoryCe face Connect în Claude Code (Codex nu primește mod-uri)
"mod"Pornește modul (<nume>@symbai: true în ~/.claude/settings.json + claude plugin install), fără versiune nouă de Connect. Un false pus de om rămâne.
"mod-retras"Oprirea centrală: scrie false și rulează claude plugin uninstall <nume>@symbai, care scoate cheia și copia din cache.

Scoaterea unui mod din pachet nu îl oprește: intrarea true și copia din cache rămân. Un mod care se poartă rău se retrage cu "mod-retras":

  • Se atinge numai un true de sub @symbai. Un false pus de om rămâne, iar un plugin cu același nume din alt marketplace nu se atinge.
  • Intrarea rămâne în manifest cu dosarul și versiunea ei: build-package.ps1 cere plugin.json pentru fiecare intrare. symbai-core nu se poate retrage.
  • Marcajul pus înapoi pe "mod" repornește modul acolo unde dezinstalarea a reușit. Unde a eșuat, a rămas false, care nu se mai deosebește de alegerea omului, deci modul rămâne oprit.
  • Connect 1.2.113 nu cunoaște marcajul: nu mai pornește un mod retras (în afară de symbai-ui, pe care îl are într-o listă fixă), dar nici nu-l oprește. Oprirea propriu-zisă vine cu versiunea de Connect de după 1.2.113.

Structură

.claude-plugin/marketplace.json     # marketplace (listează pluginul symbai-core)
plugins/symbai-core/
  .claude-plugin/plugin.json        # manifestul pluginului
  skills/<nume>/SKILL.md            # workflow-uri
  knowledge/*.md                    # cunoștințe pe module

Compatibilitate

Skill-urile urmează standardul deschis Agent Skills (SKILL.md), deci funcționează în Claude Code. Pentru alte unelte (ex. Codex) suportul poate diferi — conexiunea MCP funcționează oricum cross-tool.

Source 1 files
hooks/register.ts 133 lines
1import type { EngineInterface, Register } from 'claude-code'
2
3// What scripts/sync.ps1 prints: one line of JSON.
4type AccountReport = {
5  account: string
6  email: string | null
7  isActive: boolean
8  chats: number
9  added: number
10  updated: number
11}
12
13export type SyncReport = {
14  ok: boolean
15  busy?: boolean
16  added?: number
17  updated?: number
18  withoutConversation?: number
19  accounts?: AccountReport[]
20  errors?: string[]
21}
22
23const LAST_RUN = 'lastRunAt'
24// The store is shared by every session on this PC, so these gaps hold
25// across all of them: many open chats do not each start a sync.
26const GAP_AFTER_START_MS = 60_000
27const GAP_AFTER_TURN_MS = 5 * 60_000
28// The app reads an account's list only when it starts or the account logs in;
29// closing its window leaves it running beside the clock.
30const RESTART_HINT =
31  'Lista se reîncarcă doar la pornirea aplicației: închide Claude de tot (clic dreapta pe iconița Claude de lângă ceas → Quit) și deschide-l din nou. Celelalte conturi văd chat-urile la următoarea logare.'
32
33export const chats = (n: number): string => {
34  if (n === 1) return '1 chat'
35  const tail = n % 100
36  return n > 0 && (tail === 0 || tail >= 20) ? `${n} de chat-uri` : `${n} chat-uri`
37}
38
39async function sync($: EngineInterface, gapMs: number): Promise<SyncReport | undefined> {
40  // The app's Code tab keeps its lists under %APPDATA%: Windows only.
41  if ((await $.env.get('APPDATA')) === undefined) return undefined
42  const now = await $.clock.now()
43  const lastRun = Number((await $.store.get(LAST_RUN)) ?? 0)
44  if (now - lastRun < gapMs) return undefined
45  await $.store.set(LAST_RUN, now)
46
47  const run = await $.process.run(
48    [
49      'powershell.exe',
50      '-NoProfile',
51      '-NonInteractive',
52      '-ExecutionPolicy',
53      'Bypass',
54      '-File',
55      `${$.plugin.root}/scripts/sync.ps1`,
56    ],
57    { timeoutMs: 120_000 },
58  )
59  const line = run.stdout.trim().split(/\r?\n/).pop() ?? ''
60  try {
61    return JSON.parse(line) as SyncReport
62  } catch {
63    return { ok: false, errors: [run.stderr.trim() || `codul de ieșire ${run.exitCode}`] }
64  }
65}
66
67export function describe(report: SyncReport | undefined): string {
68  if (report === undefined) return 'Chat-uri comune: funcționează doar pe Windows, cu aplicația desktop Claude.'
69  if (report.busy) return 'Chat-uri comune: o altă sincronizare rulează chiar acum. Încearcă din nou peste un minut.'
70
71  const accounts = report.accounts ?? []
72  const lines = [`Chat-uri comune: am sincronizat lista pentru ${accounts.length} conturi de pe acest PC.`]
73  for (const account of accounts) {
74    const who = account.email ?? `cont ${account.account.slice(0, 8)} (emailul apare după prima lui sesiune)`
75    const changes = [
76      account.added > 0 ? `${account.added} noi` : '',
77      account.updated > 0 ? `${account.updated} actualizate` : '',
78    ].filter(Boolean)
79    lines.push(
80      `- ${who}${account.isActive ? ' (contul tău)' : ''}: ${chats(account.chats)}` +
81        (changes.length > 0 ? `, ${changes.join(', ')}` : ''),
82    )
83  }
84  lines.push(RESTART_HINT)
85  if ((report.withoutConversation ?? 0) > 0) {
86    lines.push(
87      `${chats(report.withoutConversation ?? 0)} nu mai au conversația salvată pe acest PC, așa că nu au fost copiate.`,
88    )
89  }
90  for (const error of report.errors ?? []) lines.push(`Eroare: ${error}`)
91
92  return lines.join('\n')
93}
94
95function syncSoon($: EngineInterface, gapMs: number): void {
96  $.clock.after(2_000, () => {
97    sync($, gapMs)
98      .then(report => {
99        const mine = report?.accounts?.find(account => account.isActive)
100        if (mine !== undefined && mine.added > 0) {
101          $.ui.toast(
102            `Chat-uri comune: ${chats(mine.added)} din alte conturi au intrat în lista ta. ${RESTART_HINT}`,
103          )
104        }
105      })
106      .catch(() => undefined)
107  })
108}
109
110export const register: Register = on => {
111  on('session.start', async ($, e, next) => {
112    await $.command.register({
113      name: 'chaturi-comune',
114      description: 'Copiază acum chat-urile tuturor conturilor Claude de pe acest PC în lista fiecărui cont.',
115    })
116    const started = await next(e)
117    syncSoon($, GAP_AFTER_START_MS)
118
119    return started
120  })
121
122  on('turn.complete', async ($, e, next) => {
123    const completed = await next(e)
124    syncSoon($, GAP_AFTER_TURN_MS)
125
126    return completed
127  })
128
129  on('command.run', { command: 'chaturi-comune' }, async $ => ({ text: describe(await sync($, 0)) })).catch(
130    () => ({ text: 'Chat-uri comune: sincronizarea nu a putut rula. Încearcă din nou.' }),
131  )
132}
133