sync SVN r18174
This commit is contained in:
193
docs/function_hooks_verificare.md
Normal file
193
docs/function_hooks_verificare.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# Verificare "function hooks" — Claude Code 2.1.274 (nativ, win32-x64)
|
||||
|
||||
Sursa de verificat: https://claudefa.st/blog/tools/hooks/function-hooks (blog tert, neoficial).
|
||||
Metoda: (1) incercare de rulare reala `/plugin-types`; (2) cautare de siruri si context in
|
||||
binarul nativ instalat, `C:\Users\mmari\.local\bin\claude.exe` (233691808 octeti, Bun-compiled,
|
||||
comitul `1efcc1361e64`). Fiecare constatare de mai jos e marcata cu sursa ei.
|
||||
|
||||
## 1. Rularea comenzii cerute
|
||||
|
||||
```
|
||||
CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude -p "/plugin-types ./types"
|
||||
```
|
||||
|
||||
Rezultat: **nu s-a generat niciun fisier**. Raspunsul modelului a fost text conversational
|
||||
("Ready — no task given yet." / la reincercare cu `--output-format json`: `"I'm ready. What
|
||||
would you like me to work on?"`). Niciun folder `types/` sau `.claude/types/` nu a aparut in
|
||||
scratchpad dupa rulare (verificat cu `ls`).
|
||||
|
||||
**Cauza identificata, nu specifica function hooks**: am testat control cu `claude -p "/help"`
|
||||
(comanda locala cea mai de baza din tot CLI-ul, intotdeauna inregistrata, fara nicio poarta de
|
||||
feature-flag). A esuat identic — modelul a primit "/help" ca text mangled si a raspuns
|
||||
conversational, in loc sa afiseze ajutorul. **Concluzie: invocarea `claude -p "<text>"` din acest
|
||||
mediu nu ruteaza deloc prin dispecerul de comenzi locale ("slash commands")** — cererea merge
|
||||
direct la model ca prompt text. Din `--debug-file`, header-ul de atribuire arata
|
||||
`cc_entrypoint=sdk-cli`, adica sesiunea porneste prin calea SDK, nu prin REPL-ul interactiv complet;
|
||||
acolo comenzile locale par sa nu fie interceptate. Deci esecul lui `/plugin-types` **nu e dovada
|
||||
ca function hooks sunt dezactivate** — e o limitare a modului de invocare folosit aici, valabila
|
||||
si pentru comenzi complet neutre ca `/help`. N-am putut testa varianta interactiva (fara TTY in
|
||||
acest mediu).
|
||||
|
||||
`claude --help` si `claude plugin --help` (rulate separat, capturate integral) **nu listeaza**
|
||||
nicio comanda `plugin-types` la nivel de CLI top-level — motivul e ca `/plugin-types` e o comanda
|
||||
*in-sesiune* ("slash command"), nu o subcomanda a executabilului `claude`, deci absenta ei din
|
||||
`--help` e normala si nu spune nimic despre activare.
|
||||
|
||||
## 2. Ce exista REAL in binar (cautare de siruri, cu offset de octet verificabil)
|
||||
|
||||
Nu s-au generat `.d.ts`, deci n-am putut citi declaratii TypeScript complete ca "dovada
|
||||
canonica" ceruta in sarcina. In schimb, am gasit in binar cod sursa minificat (nu doar siruri
|
||||
izolate) care confirma mecanismul de facto. Tot ce urmeaza e citat verbatim din binar, cu offset.
|
||||
|
||||
### 2a. Flag-ul si poarta lui reala
|
||||
|
||||
La offset ~103270720 (grep -a -b), blocul de cod al flag-ului:
|
||||
|
||||
```
|
||||
var kYe="tengu_plugin_hooks_modules";
|
||||
var Azt=()=>!1;
|
||||
var AFe=()=>a.CLAUDE_CODE_ENABLE_FUNCTION_HOOKS??P(kYe,Azt());
|
||||
var h8=()=>AFe()&&!qb()&&!Br("hooks")&&!zm();
|
||||
```
|
||||
|
||||
Interpretare directa din cod:
|
||||
- flag-ul GrowthBook real se numeste **`tengu_plugin_hooks_modules`**, default **oprit** (`Azt=()=>!1`).
|
||||
- `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS` e o suprascriere locala peste acel flag (`??`) — confirma
|
||||
exact ce zice blogul despre numele variabilei de mediu.
|
||||
- **dar** poarta finala folosita in productie, `h8()`, cere si `!qb() && !Br("hooks") && !zm()`
|
||||
— trei conditii suplimentare. Numele acestor functii sunt minificate si reciclate in zeci de
|
||||
module din bundle (acelasi nume `qb`/`Br`/`zm` apare cu corpuri complet diferite in alte
|
||||
scope-uri), deci **nu pot atribui cu certitudine ce verifica exact aici** fara deminificare
|
||||
completa — onest: aceasta e limita cercetarii, nu o concluzie.
|
||||
- Alaturi, la acelasi offset, un tabel de atribuire a sursei flag-ului pentru afisare in UI:
|
||||
`{override:"from a local override", payload:"from GrowthBook (this session's payload)",
|
||||
disk:"from GrowthBook (the disk cache of an earlier session)", disabled:"from the default
|
||||
(GrowthBook is off ...)"}` — confirma ca e un flag GrowthBook cu override local, exact
|
||||
mecanismul descris de blog.
|
||||
|
||||
### 2b. Comanda `/plugin-types` — confirmata REAL, dar NEgatata de flag
|
||||
|
||||
La offset 203438732, definitia completa a comenzii (citat verbatim):
|
||||
|
||||
```
|
||||
var mer=Object.freeze({type:"local",name:"plugin-types",
|
||||
description:"Write claude-code.d.ts, claude-code-plugins.d.ts and claude-code-mcp.d.ts:
|
||||
the plugin API's TypeScript declarations, the enabled plugins' type contracts and the
|
||||
inputs of the connected MCP tools, for typing a hooks module against this session",
|
||||
argumentHint:"[dir]", supportsNonInteractive:!0,
|
||||
load:()=>import("B:/~BUN/root/chunk-0rpsm23r.js")});
|
||||
```
|
||||
|
||||
Important: **acest obiect n-are nicio conditie `isEnabled`/gate legata de `h8()` sau de
|
||||
flag** — e inregistrata neconditionat. Descrierea confirma explicit sintagma "hooks module"
|
||||
din blog: comanda exista ca sa tipizeze "a hooks module against this session". Deci comanda in
|
||||
sine e reala si documentata intern, indiferent de starea flag-ului; problema empirica de mai
|
||||
sus (sectiunea 1) e doar despre modul de invocare `-p` din acest mediu.
|
||||
|
||||
### 2c. Lista REALA de evenimente si API-uri ("scan manifest"), gasita ca date, nu ca documentatie
|
||||
|
||||
La offset 223160560 exista un manifest static de tip "scan" folosit (aparent) pentru analiza
|
||||
statica / sandboxing a unui modul de plugin, cu lista completa si explicita:
|
||||
|
||||
```js
|
||||
scan: {
|
||||
hooks: ["session.start","ui.render","command.run","ui.close","ui.focus","ui.scroll",
|
||||
"tool.call","prompt.submit"],
|
||||
calls: ["clock.after","clock.every","clock.now","command.register","fs.list","fs.read",
|
||||
"fs.stat","process.run","session.id","session.messages","store.get","store.set",
|
||||
"telemetry.log","telemetry.mark","ui.close","ui.invalidate","ui.log","ui.open",
|
||||
"ui.resolve","ui.status"]
|
||||
}
|
||||
```
|
||||
|
||||
Aceasta e cea mai tare dovada gasita — e o **lista de date**, nu un string de proza, deci
|
||||
foarte probabil chiar suprafata reala (sau foarte apropiata) a API-ului de hooks module:
|
||||
|
||||
- **evenimente de hook confirmate**: `session.start`, `ui.render`, `command.run`, `ui.close`,
|
||||
`ui.focus`, `ui.scroll`, `tool.call`, `prompt.submit` (8 la numar).
|
||||
- **`turn.complete` si `turn.start` NU sunt in lista de evenimente de hook**, desi cele doua
|
||||
siruri exista in alta parte a binarului (24, respectiv 68 aparitii) — apartin mecanismului
|
||||
intern de motor ("engine turn 1 start/end", vazut si in log-ul de debug la rularea reala),
|
||||
nu suprafetei de hooks expuse pluginurilor.
|
||||
- **`prompt.submit` e confirmat**, si separat, la offset 206959908, exista codul intern real
|
||||
care implementeaza acest hook point: un pipeline `core`/`managed` cu posibilitate de a
|
||||
rescrie textul promptului (`"prompt.submit: text rewritten by a hook (...)"`) sau de a-l
|
||||
bloca (`"Prompt dropped by a hook: ..."`). Semnatura exacta gasita e apelul
|
||||
`.prompt.submit({submission, origin, turnId, shouldWait})` — **nu am gasit litera `$` ca
|
||||
alias/receiver exact** in siruri; forma `$.prompt.submit({text})` din blog e plauzibila ca
|
||||
sugar-syntax peste acest mecanism, dar nu e confirmata verbatim.
|
||||
- **API-uri de tip "calls" confirmate ca namespace-uri cu metode**: `fs.read/list/stat`
|
||||
(deci `$.fs` probabil e un namespace, nu o valoare simpla), `store.get/set`,
|
||||
`clock.after/every/now`, `session.id/messages` — coincide cu ce cerea sarcina sa verific
|
||||
(`$.session.messages()`, `$.fs`, `$.store`, `$.clock.every`), dar iar, prefixul `$.` in sine
|
||||
nu apare ca sir literal langa aceste nume — e o inferenta rezonabila, nu o citare directa.
|
||||
|
||||
### 2d. Tokeni / context / usage / compactare — CAUTATE EXPLICIT, NU GASITE
|
||||
|
||||
Am cautat explicit `token`, `usage`, `context`, `compact` in vecinatatea manifestului de mai
|
||||
sus si in restul zonei de "function hooks". **Niciunul dintre cele 20 de `calls` sau 8 `hooks`
|
||||
de mai sus nu are legatura cu tokeni, context window, usage sau compactare.** Sirurile
|
||||
`contextWindow` (8 aparitii) si `compact` (405 aparitii) exista din abundenta in binar, dar in
|
||||
alte module (afisarea usage-ului in `--output-format json`, autocompact intern al motorului
|
||||
— vazut si in logul de debug: `autocompact: tokens=[REDACTED] level=ok effectiveWindow=980000`),
|
||||
**nu ca hook sau call disponibil unui modul de function hooks**. Nu exista dovada in acest
|
||||
binar ca un modul de hooks ar putea citi tokenii ramasi sau starea de compactare.
|
||||
|
||||
### 2e. Forma `register` si `hooks/hooks.json`
|
||||
|
||||
Doua descoperiri, ambele reale, dar **doua lucruri diferite**:
|
||||
|
||||
1. **`hooks.json` din binar (27 aparitii) e manifestul VECHI/existent de plugin-hooks**
|
||||
(PreToolUse, SessionStart etc. — cel folosit deja de pluginul `ponytail` din acest proiect,
|
||||
vazut in logul de debug: `Read manifest hooks for plugin ponytail (enabled=true):
|
||||
./hooks/claude-codex-hooks.json`). Contextul din binar confirma: sirul e `"plugin
|
||||
hooks.json"`, langa mesaje despre `SKILL.md` si actualizarea regulilor de auto-mode/permisiuni
|
||||
— sistemul clasic de hooks pe evenimente de tool-use, nesuprapus cu "function hooks".
|
||||
|
||||
2. **Forma `register` pentru "function hooks" (modulul nou)**, gasita in doua exemple interne
|
||||
reale de pluginuri deja construite cu acest mecanism:
|
||||
- `tengu_quiet_dolphin` — "panoul de diff ca plugin: /diff", cu
|
||||
`isAvailable:()=>At` unde `At=()=>h8()&&lu(Rr(),bt)` — **confirma ca h8() (poarta de
|
||||
function hooks descrisa la 2a) chiar gateaza un plugin real deja construit**, nu doar un
|
||||
flag mort.
|
||||
- `tengu_tips_mod` — "spinner tips as a plugin", cu forma exacta:
|
||||
```js
|
||||
var P=(e)=>({register:(o)=>{e.registerHooks(o,x())}});
|
||||
```
|
||||
adica modulul exporta un `register(engine)` care apeleaza
|
||||
`engine.registerHooks(implementareHooks, apiSuplimentar)`. E cea mai apropiata dovada
|
||||
gasita de "forma exacta a functiei register", dar e exemplul unui plugin intern concret,
|
||||
nu semnatura generica documentata explicit undeva ca atare.
|
||||
|
||||
## VERDICT
|
||||
|
||||
Se poate construi o bucla "prag context -> scrie handoff -> /clear -> reia din handoff" complet
|
||||
automat, FARA interventia utilizatorului, folosind acest surface?
|
||||
|
||||
**Nu, nu cu ce am vazut efectiv in acest binar.** Motive, punct cu punct:
|
||||
|
||||
1. Suprafata de hooks confirmata (`session.start`, `ui.*`, `command.run`, `tool.call`,
|
||||
`prompt.submit`) **nu contine niciun eveniment sau apel legat de prag de context, tokeni,
|
||||
usage sau compactare** (sectiunea 2d) — deci un modul de hooks n-ar avea de unde sa afle
|
||||
"am trecut de 200k tokeni" din interior. Ar trebui sa deduca asta indirect (ex. numarand
|
||||
caractere din `session.messages()`), fara nicio garantie ca se potriveste cu tokenizarea
|
||||
reala sau cu `autocompact` intern.
|
||||
2. Nu exista niciun hook de tipul "inainte de compactare" / "sesiune se inchide" in lista —
|
||||
deci nu exista un punct de agatare curat pentru "scrie handoff chiar inainte sa se piarda
|
||||
contextul".
|
||||
3. `/clear` (sau relansarea sesiunii) nu apare in `calls`-urile confirmate (`command.register`
|
||||
exista, dar a inregistra o comanda noua nu e totuna cu a declansa `/clear` programatic din
|
||||
interiorul unui hook).
|
||||
4. Flag-ul e in continuare oprit implicit (`tengu_plugin_hooks_modules` default `!1`),
|
||||
marcat "early access" chiar in textul din comanda `/plugin-types` insasi
|
||||
("module 'claude-code', early access: it may change between releases") — deci si daca
|
||||
API-ul de mai sus ar acoperi cazul, Anthropic il trateaza explicit ca nestabil.
|
||||
5. **Nu am reusit sa validam empiric nimic din surface** (n-am putut genera `.d.ts` din cauza
|
||||
limitarii de mediu descrise la sectiunea 1) — tot ce e mai sus e din citirea codului
|
||||
minificat, nu din declaratii TypeScript generate si citite ca atare, cum cerea procedura.
|
||||
|
||||
Ce ar lipsi/ar trebui reincercat ca sa se stie sigur: rulare **interactiva** reala (TTY, nu
|
||||
`-p`/SDK) cu `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1`, ca sa se vada daca `/plugin-types` chiar
|
||||
scrie fisierele si daca `h8()` se evalueaza `true` in acel context — asta ar da acces la
|
||||
declaratiile TypeScript reale si ar inchide toate necunoscutele de mai sus (in special conditiile
|
||||
`qb()`/`Br("hooks")`/`zm()` neatribuite cu certitudine).
|
||||
Reference in New Issue
Block a user