@zeph-to/cli 2.4.0 → 2.5.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/dist/listener.d.ts +14 -0
- package/dist/listener.d.ts.map +1 -1
- package/dist/listener.js +0 -0
- package/dist/remote-agents.d.ts +105 -1
- package/dist/remote-agents.d.ts.map +1 -1
- package/dist/remote-agents.js +283 -34
- package/dist/zeph-core.generated.d.ts +3 -3
- package/dist/zeph-core.generated.d.ts.map +1 -1
- package/dist/zeph-core.generated.js +3 -3
- package/package.json +1 -1
package/dist/listener.d.ts
CHANGED
|
@@ -32,6 +32,20 @@ interface AgentSession {
|
|
|
32
32
|
agentSessionId?: string | null;
|
|
33
33
|
project: string;
|
|
34
34
|
label?: string | null;
|
|
35
|
+
/**
|
|
36
|
+
* The name the agent itself calls this session by, when its registry
|
|
37
|
+
* exposes one (Claude Code's `zeph-to-95`). A live read, not user intent —
|
|
38
|
+
* the phone's rename still wins over it. Null where the agent has no name
|
|
39
|
+
* concept, where the pane's session could not be identified, or where the
|
|
40
|
+
* name is blank.
|
|
41
|
+
*
|
|
42
|
+
* Deliberately NOT `sessionName`: everywhere else in this file and on the
|
|
43
|
+
* wire that word means the tmux session name (`agentSessionName` in a
|
|
44
|
+
* push, `AgentWatchRecord.sessionName` on the server). Two names for a
|
|
45
|
+
* session is already the problem this field exists to solve; reusing the
|
|
46
|
+
* word for both would put the ambiguity in the type.
|
|
47
|
+
*/
|
|
48
|
+
providerSessionName?: string | null;
|
|
35
49
|
createdAt?: string;
|
|
36
50
|
lastActivityAt?: string;
|
|
37
51
|
/**
|
package/dist/listener.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA0BH,OAAO,EAA0C,KAAK,SAAS,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACxH,OAAO,EAAiD,KAAK,UAAU,EAA4C,MAAM,kBAAkB,CAAC;AAE5I,OAAO,EAA4E,KAAK,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACvI,OAAO,EAA6C,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAmCtG,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAElD,UAAU,YAAY;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,qBAAqB,GAC9B,MAAM,SAAS,YAAY,EAAE,EAC7B,MAAK,MAAmB,KACzB,oBAAoB,EAYtB,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,OAAO,oBAAoB,EAAE,KAAG,MACP,CAAC;AAEnE,eAAO,MAAM,mBAAmB,GAAI,UAAU,YAAY,EAAE,KAAG,MAS7C,CAAC;AAEnB;6BAC6B;AAC7B,eAAO,MAAM,iBAAiB,GAC1B,aAAa,MAAM,EACnB,qBAAqB,MAAM,GAAG,IAAI,EAClC,cAAc,MAAM,EACpB,OAAO,MAAM,KACd,OAEoD,CAAC;AAqBxD,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAA+B,CAAC;AAenF,eAAO,MAAM,cAAc,GACvB,SAAS,MAAM,EACf,MAAK,MAAmB,EACxB,OAAM,MAAU,KACjB,OAgBF,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,IAO7D,CAAC;AAgGF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,KAAG,MAAM,EAAE,GAAG,IAQvD,CAAC;AA0CF;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,QAAO,IAG5C,CAAC;AA8NF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAK3F,CAAC;AAEF,UAAU,QAAQ;IACd,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAiDD;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,QAAQ,KAAG,qBAAqB,GAAG,IAGhE,CAAC;AA0BZ,iBAAiB;AACjB,eAAO,MAAM,kBAAkB,QAAO,IAErC,CAAC;AAWF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC3B,MAAM,MAAM,EACZ,WAAW,SAAS,EACpB,UAAU,MAAM,GAAG,IAAI,EACvB,MAAK,MAAmB,KACzB,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,gBAAgB,GAAG,aAAa,CAmB/D,CAAC;AAWF,MAAM,WAAW,YAAY;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACnB;AASD,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,GAAI,KAAK,OAAO,KAAG,IAWhD,CAAC;AAEF,iBAAiB;AACjB,eAAO,MAAM,mBAAmB,QAAO,IAGtC,CAAC;AAEF,MAAM,WAAW,QAAQ;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GACzB,WAAW,WAAW,CAAC,MAAM,CAAC,EAC9B,UAAS,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAsB,KAC9D,QAAQ,EAgBV,CAAC;AAWF,MAAM,WAAW,aAAa;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,uBAAuB,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,aAAa,KAAG,cAAc,GAAG,IAmBzE,CAAC;AAgBF;;kDAEkD;AAClD,eAAO,MAAM,mBAAmB,QAAY,CAAC;AAK7C,MAAM,WAAW,gBAAgB;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;4EACwE;IACxE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACrD;wEACoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;sCACkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACnB;AAsGD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAC/B,KAAK,gBAAgB,EACrB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,KAC9C,OA2CF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAC9B,KAAK,eAAe,EACpB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,KAC9C,OA+CF,CAAC;AAWF,MAAM,WAAW,oBAAoB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,6BAA6B,CAAC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GACnC,KAAK,oBAAoB,EACzB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,KAC9C,OAoDF,CAAC;AAEF,MAAM,WAAW,kBAAkB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,2BAA2B,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;CACd;AA0BD,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,OAAQ,CAAC;AAI1C;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GACjC,KAAK,kBAAkB,EACvB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,KAC9C,OA0DF,CAAC;AAiBF;+EAC+E;AAC/E,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAG5C,MAAM,WAAW,oBAAoB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IAClC,OAAO,EAAE,+BAA+B,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;sCACkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;0EACsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;oEACgE;IAChE,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACtB;AA0CD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,0BAA0B,GACnC,KAAK,oBAAoB,EACzB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,KAC9C,OA8DF,CAAC;AAqEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GACtB,SAAS,MAAM,EACf,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KACjD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAKlC,CAAC;AASF;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,EAAE,YAAY,MAAM,KAAG,MAClB,CAAC;AAUpD;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,GAChC,aAAa,MAAM,EACnB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,EAC7C,SAAQ,MAAM,EAA8B,KAC7C,IAuBF,CAAC;AAcF,MAAM,WAAW,aAAa;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAQD,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAKtC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,eAAe,OAAQ,CAAC;AAOrC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GAAI,aAAa,MAAM,GAAG,IAAI,EAAE,KAAK,MAAM,KAAG,MACgC,CAAC;AAEzG,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH;;gEAEgE;AAChE,eAAO,MAAM,cAAc,GAAI,QAAQ,WAAW,EAAE,KAAK,MAAM,KAAG,OAGxB,CAAC;AAE3C,eAAO,MAAM,cAAc,GAAI,QAAQ,WAAW,EAAE,KAAK,MAAM,KAAG,OAYjE,CAAC;AAqBF,eAAO,MAAM,eAAe,QAAS,CAAC;AAMtC,eAAO,MAAM,sBAAsB,IAAI,CAAC;AA6GxC,eAAO,MAAM,UAAU,GAAI,aAAa,MAAM,KAAG,IAuBhD,CAAC;AAEF,eAAO,MAAM,cAAc,QAAO,IAGjC,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,OAAO,EAAE,oBAAoB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;mEAC+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;4EAMwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;0CAMsC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,yBAAyB,CAAC;CACzC,CAAC;AAEF;;;gDAGgD;AAChD,MAAM,MAAM,gBAAgB,GAAG;IAC3B,OAAO,EAAE,oBAAoB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,cAAc,GAAG,aAAa,GAAG,gBAAgB,CAAC;IACrH;;+EAE2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;sEAEkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,aAAa,MAAM,KAAG,OAChB,CAAC;AAqC1C;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GACzB,UAAU;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,EACjD,aAAa,MAAM,EACnB,sBAAsB,MAAM,EAC5B,OAAO;IAAE,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,KAChF,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAkBnC,CAAC;AAEF;;;;GAIG;AASH,eAAO,MAAM,mBAAmB,GAC5B,KAAK,aAAa,EAClB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,KAC9C,OAmQF,CAAC;AAWF;;;uBAGuB;AACvB,MAAM,WAAW,iBAAiB;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;+EAI2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;kFAK8E;IAC9E,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;8DAE8D;AAC9D,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC;;uDAEuD;AACvD,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,kFAAkF;AAClF,KAAK,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AAE7D,+BAA+B;AAC/B,KAAK,cAAc,GAAG,cAAc,GAAG;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB;kEAC8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;wEACoE;IACpE,MAAM,EAAE,OAAO,CAAC;CACnB,CAAC;AAOF,KAAK,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAuCtF;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,iBAAiB,KAAG,UAsC7D,CAAC;AAoBF;;;6DAG6D;AAC7D,eAAO,MAAM,eAAe,KAAK,CAAC;AA6ClC;;;;sDAIsD;AACtD,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,QAAO,OAAO,CAAC,IAAI,CAAsB,CAAC;AA6G3E;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC3B,KAAK,iBAAiB,EACtB,MAAM,aAAa,KACpB,OAqCF,CAAC;AAEF,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAAO,aAmFzC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,QAAO,YAAY,EAAuC,CAAC;AAIvF;;;;;GAKG;AACH,UAAU,kBAAkB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,QAAQ;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;sEACkE;IAClE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;sEACkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED,UAAU,cAAc;IACpB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACpD,0EAA0E;IAC1E,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACxD,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;IAC1D,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACtE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,oEAAoE;IACpE,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzF,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC7C;sEACkE;IAClE,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AA2BD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAC1B,SAAS,MAAM,EACf,MAAM,MAAM,EACZ,MAAK,MAAM,MAAiB,KAC7B,OAUF,CAAC;AA0DF,eAAO,MAAM,oBAAoB,GAAI,KAAK;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KAAG,IAE/E,CAAC;AA2FF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACtB,MAAK,MAAmB,EACxB,MAAK,MAAwB,EAC7B,MAAK,MAA0B,KAChC,MAaF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,GACnB,MAAM,QAAQ,EACd,OAAM,cAAmB,KAC1B,OAAO,CAAC,OAAO,CAgDjB,CAAC;AAcF,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,MAIhD,CAAC;AA4DF,eAAO,MAAM,uBAAuB,GAAI,OAAO,MAAM,KAAG,MA2BvD,CAAC;AA2QF;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GACrB,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,EACtC,QAAQ;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAC1B,SAAS,MAAM,KAChB,MAAM,GAAG,IAIX,CAAC;AA0DF,eAAO,MAAM,cAAc,GAAU,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAG,OAAO,CAAC,MAAM,CAsI3F,CAAC"}
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"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"}
|
package/dist/listener.js
CHANGED
|
Binary file
|
package/dist/remote-agents.d.ts
CHANGED
|
@@ -28,6 +28,17 @@ export interface RemoteAgent {
|
|
|
28
28
|
* then reports agentSessionId: null.
|
|
29
29
|
*/
|
|
30
30
|
resolveSessionId?: (paneCwd: string, panePid?: number) => string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the name the agent calls this session by — what the user sees in
|
|
33
|
+
* their own terminal, which the phone shows instead of the computed
|
|
34
|
+
* `<project> · <Agent> #N` label.
|
|
35
|
+
*
|
|
36
|
+
* Same shape as `resolveSessionId` and the same EXTENSION POINT rule: a row
|
|
37
|
+
* carries this only once that agent's name store is confirmed. Cursor and
|
|
38
|
+
* Gemini never will — their state files hold ids, cwds and timestamps and no
|
|
39
|
+
* name at all, so there is nothing to read and the computed label stands.
|
|
40
|
+
*/
|
|
41
|
+
resolveSessionName?: (paneCwd: string, panePid?: number) => string | null;
|
|
31
42
|
}
|
|
32
43
|
/**
|
|
33
44
|
* Locate the most recent Claude Code session UUID for the working
|
|
@@ -38,11 +49,43 @@ export interface RemoteAgent {
|
|
|
38
49
|
* claudeSessionCache.
|
|
39
50
|
*/
|
|
40
51
|
export declare const detectClaudeSessionId: (cwd: string) => string | null;
|
|
41
|
-
interface PidSessionRecord {
|
|
52
|
+
export interface PidSessionRecord {
|
|
42
53
|
pid: number;
|
|
43
54
|
sessionId: string;
|
|
44
55
|
cwd: string;
|
|
56
|
+
/**
|
|
57
|
+
* What Claude Code calls this session (`zeph-to-95` when derived from the
|
|
58
|
+
* cwd, free text once named). Optional: an older CC writes the record
|
|
59
|
+
* without it, and a record without a name is still a valid id match.
|
|
60
|
+
*/
|
|
61
|
+
name?: string;
|
|
45
62
|
}
|
|
63
|
+
export interface ProcTable {
|
|
64
|
+
/** ppid → its direct children, for walking a pane's process tree. */
|
|
65
|
+
children: Map<number, number[]>;
|
|
66
|
+
/** pid → process start time in epoch ms. Only pids whose `lstart` parsed. */
|
|
67
|
+
startTimes: Map<number, number>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Parse `ps -axo pid=,ppid=,lstart=`. A row is `<pid> <ppid> [<lstart>]`, e.g.
|
|
71
|
+
* ` 1 0 Fri Aug 7 11:12:59 2026 ` — note the two spaces before a
|
|
72
|
+
* single-digit day and the trailing padding.
|
|
73
|
+
*
|
|
74
|
+
* The third field is OPTIONAL in the pattern, and that is load-bearing rather
|
|
75
|
+
* than defensive. Requiring it would mean that on any machine whose `ps` prints
|
|
76
|
+
* a different `lstart` shape, EVERY row fails to match, `children` comes back
|
|
77
|
+
* empty, `collectDescendantPids` answers `{rootPid}`, and
|
|
78
|
+
* `detectClaudeSessionByPid` finds nothing — dropping Claude Code back to the
|
|
79
|
+
* mtime heuristic and its identity theft (see CLAUDE_SESSIONS_DIR above). The
|
|
80
|
+
* parent links must survive an unreadable timestamp; only the start time is
|
|
81
|
+
* allowed to go missing, and every consumer of `startTimes` treats an absent
|
|
82
|
+
* entry as "no match" rather than guessing.
|
|
83
|
+
*/
|
|
84
|
+
export declare const parseProcTable: (table: string) => ProcTable;
|
|
85
|
+
/** Start times for this cycle's snapshot. Empty when `ps` is unavailable. */
|
|
86
|
+
export declare const psStartTimes: () => Map<number, number>;
|
|
87
|
+
/** pid set of `rootPid` + all descendants, from one `ps` snapshot. */
|
|
88
|
+
export declare const collectDescendantPids: (rootPid: number) => Set<number>;
|
|
46
89
|
/** Test seam for the pid-based resolver. */
|
|
47
90
|
export interface PidResolveDeps {
|
|
48
91
|
records?: PidSessionRecord[];
|
|
@@ -53,8 +96,66 @@ export interface PidResolveDeps {
|
|
|
53
96
|
* process tree AND whose cwd matches (guards against OS pid reuse
|
|
54
97
|
* leaving a stale record pointing elsewhere). Null → caller falls back
|
|
55
98
|
* to the mtime heuristic.
|
|
99
|
+
*
|
|
100
|
+
* Returns the whole record so the id and the name come from one lookup — they
|
|
101
|
+
* describe the same session, and reading the directory twice per cycle to get
|
|
102
|
+
* them separately is what the cache above exists to avoid.
|
|
56
103
|
*/
|
|
104
|
+
export declare const detectClaudeSessionByPid: (panePid: number, paneCwd: string | null, deps?: PidResolveDeps) => PidSessionRecord | null;
|
|
57
105
|
export declare const detectClaudeSessionIdByPid: (panePid: number, paneCwd: string | null, deps?: PidResolveDeps) => string | null;
|
|
106
|
+
/**
|
|
107
|
+
* The name of the session running in this pane. No mtime fallback exists here:
|
|
108
|
+
* the transcript filenames the heuristic walks carry a UUID and nothing else,
|
|
109
|
+
* so an older CC without `~/.claude/sessions` yields no name and the phone
|
|
110
|
+
* keeps the computed label.
|
|
111
|
+
*/
|
|
112
|
+
export declare const detectClaudeSessionNameByPid: (panePid: number, paneCwd: string | null, deps?: PidResolveDeps) => string | null;
|
|
113
|
+
/**
|
|
114
|
+
* The row whose timestamp is closest to when one of the pane's processes started,
|
|
115
|
+
* within {@link PROC_MATCH_TOLERANCE_MS}. Null when nothing qualifies — including
|
|
116
|
+
* when no pid in the tree has a known start time, which is why the start times
|
|
117
|
+
* are collected before any row is compared rather than defaulted to zero.
|
|
118
|
+
*/
|
|
119
|
+
export declare const pickRowByProcStart: <T>(rows: readonly T[], tsMsOf: (row: T) => number | null, startTimes: Map<number, number>, pids: Set<number>) => T | null;
|
|
120
|
+
/**
|
|
121
|
+
* Read rows from a SQLite file as JSON. Null on every failure — no `sqlite3` on
|
|
122
|
+
* PATH, a locked or corrupt database, a schema that moved — because a missing
|
|
123
|
+
* name costs the computed label and nothing else.
|
|
124
|
+
*
|
|
125
|
+
* The query carries no parameters BY DESIGN: SQL passed to the `sqlite3` binary
|
|
126
|
+
* as an argv string has nowhere to bind `?` to, so interpolating a cwd would
|
|
127
|
+
* make this file the place that has to know SQLite quoting rules. Callers select
|
|
128
|
+
* the columns they need and filter in JS instead; the stores hold tens of rows,
|
|
129
|
+
* not millions. The `timeout` keeps a locked database from holding up a report
|
|
130
|
+
* cycle that runs every five seconds.
|
|
131
|
+
*/
|
|
132
|
+
export declare const sqliteJson: (dbPath: string, sql: string) => unknown[] | null;
|
|
133
|
+
/** Test seam for the store-backed resolvers. `rows: null` = the read failed. */
|
|
134
|
+
export interface StoreResolveDeps {
|
|
135
|
+
rows?: unknown[] | null;
|
|
136
|
+
startTimes?: Map<number, number>;
|
|
137
|
+
descendants?: Set<number>;
|
|
138
|
+
}
|
|
139
|
+
export declare const detectHermesSessionName: (paneCwd: string, panePid?: number, deps?: StoreResolveDeps) => string | null;
|
|
140
|
+
/**
|
|
141
|
+
* The highest-numbered match, numerically. Codex versions its state file
|
|
142
|
+
* (`state_5.sqlite` today) and moves to the next number on a schema migration,
|
|
143
|
+
* so hard-coding a name would silently stop reading after an upgrade. Sorting
|
|
144
|
+
* the strings would break at `state_10` vs `state_9`.
|
|
145
|
+
*/
|
|
146
|
+
export declare const newestVersionedDb: (entries: readonly string[], pattern: RegExp) => string | null;
|
|
147
|
+
/**
|
|
148
|
+
* No `source` filter, unlike the Hermes reader's `source = 'cli'`. The column
|
|
149
|
+
* exists here too (alongside `thread_source`), but Codex is unauthenticated on
|
|
150
|
+
* every machine measured so far and its `threads` table is empty, so which
|
|
151
|
+
* values mark a terminal session is unknown — and a wrong guess filters out
|
|
152
|
+
* every row, which fails as "no name ever" rather than loudly. A thread from a
|
|
153
|
+
* non-terminal frontend is therefore eligible to match, and it lands in the same
|
|
154
|
+
* accepted misjoin as two terminals in the same directory: it needs the same cwd
|
|
155
|
+
* AND a creation time within the tolerance of a process in this pane. Add the
|
|
156
|
+
* filter once the values can be observed.
|
|
157
|
+
*/
|
|
158
|
+
export declare const detectCodexSessionName: (paneCwd: string, panePid?: number, deps?: StoreResolveDeps) => string | null;
|
|
58
159
|
declare const REMOTE_AGENT_TABLE: readonly [{
|
|
59
160
|
readonly kind: "claude";
|
|
60
161
|
readonly displayName: "Claude Code";
|
|
@@ -62,11 +163,13 @@ declare const REMOTE_AGENT_TABLE: readonly [{
|
|
|
62
163
|
readonly subcommands: readonly ["cc", "claude"];
|
|
63
164
|
readonly quitCommand: "/exit";
|
|
64
165
|
readonly resolveSessionId: (paneCwd: string, panePid: number | undefined) => string | null;
|
|
166
|
+
readonly resolveSessionName: (paneCwd: string, panePid: number | undefined) => string | null;
|
|
65
167
|
}, {
|
|
66
168
|
readonly kind: "codex";
|
|
67
169
|
readonly displayName: "Codex CLI";
|
|
68
170
|
readonly binary: "codex";
|
|
69
171
|
readonly subcommands: readonly ["codex"];
|
|
172
|
+
readonly resolveSessionName: (paneCwd: string, panePid?: number, deps?: StoreResolveDeps) => string | null;
|
|
70
173
|
}, {
|
|
71
174
|
readonly kind: "cursor";
|
|
72
175
|
readonly displayName: "Cursor CLI";
|
|
@@ -82,6 +185,7 @@ declare const REMOTE_AGENT_TABLE: readonly [{
|
|
|
82
185
|
readonly displayName: "Hermes";
|
|
83
186
|
readonly binary: "hermes";
|
|
84
187
|
readonly subcommands: readonly ["hermes"];
|
|
188
|
+
readonly resolveSessionName: (paneCwd: string, panePid?: number, deps?: StoreResolveDeps) => string | null;
|
|
85
189
|
}];
|
|
86
190
|
/** Closed union of remote-controllable agent kinds, derived from the table above. */
|
|
87
191
|
export type AgentKind = (typeof REMOTE_AGENT_TABLE)[number]['kind'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-agents.d.ts","sourceRoot":"","sources":["../src/remote-agents.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,WAAW;IACxB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"remote-agents.d.ts","sourceRoot":"","sources":["../src/remote-agents.ts"],"names":[],"mappings":"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"}
|
package/dist/remote-agents.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.matchAgentByPaneCommand = exports.findAgentBySubcommand = exports.REMOTE_AGENTS = exports.detectClaudeSessionIdByPid = exports.detectClaudeSessionId = void 0;
|
|
3
|
+
exports.matchAgentByPaneCommand = exports.findAgentBySubcommand = exports.REMOTE_AGENTS = exports.detectCodexSessionName = exports.newestVersionedDb = exports.detectHermesSessionName = exports.sqliteJson = exports.pickRowByProcStart = exports.detectClaudeSessionNameByPid = exports.detectClaudeSessionIdByPid = exports.detectClaudeSessionByPid = exports.collectDescendantPids = exports.psStartTimes = exports.parseProcTable = exports.detectClaudeSessionId = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Remote-control agent registry — the single table behind every
|
|
6
6
|
* `zeph <agent>` subcommand, the listener's pane matching, and the
|
|
@@ -20,6 +20,45 @@ const fs_1 = require("fs");
|
|
|
20
20
|
const os_1 = require("os");
|
|
21
21
|
const path_1 = require("path");
|
|
22
22
|
const child_process_1 = require("child_process");
|
|
23
|
+
/**
|
|
24
|
+
* A per-key TTL cache, bounded so a long-lived listener that has seen many keys
|
|
25
|
+
* cannot grow without limit. `get` returns a wrapper rather than the value so a
|
|
26
|
+
* cached `null` is distinguishable from a miss, and `set` returns what it stored
|
|
27
|
+
* so callers read as one expression.
|
|
28
|
+
*
|
|
29
|
+
* Eviction drops the first key in insertion order, which is the oldest entry a
|
|
30
|
+
* key was FIRST written under — refreshing a key does not move it. With a bound
|
|
31
|
+
* of 64 keys against a handful of live panes that never matters; a workload that
|
|
32
|
+
* genuinely cycles more keys than the bound would want a real LRU.
|
|
33
|
+
*/
|
|
34
|
+
const keyedTtlCache = (ttlMs, max = 64) => {
|
|
35
|
+
const entries = new Map();
|
|
36
|
+
return {
|
|
37
|
+
get: (key) => {
|
|
38
|
+
const hit = entries.get(key);
|
|
39
|
+
return hit && hit.expiresAt > Date.now() ? hit : undefined;
|
|
40
|
+
},
|
|
41
|
+
set: (key, value) => {
|
|
42
|
+
if (entries.size >= max) {
|
|
43
|
+
const oldest = entries.keys().next().value;
|
|
44
|
+
if (oldest !== undefined)
|
|
45
|
+
entries.delete(oldest);
|
|
46
|
+
}
|
|
47
|
+
entries.set(key, { value, expiresAt: Date.now() + ttlMs });
|
|
48
|
+
return value;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* A name is only worth carrying if it has visible characters. Renderers treat
|
|
54
|
+
* `''` as falsy and fall back on their own, but the change fingerprints on both
|
|
55
|
+
* sides of the wire collapse `undefined`/`null` and would ship a blank string as
|
|
56
|
+
* a real change — a report per cycle that says nothing.
|
|
57
|
+
*/
|
|
58
|
+
const nonBlank = (value) => {
|
|
59
|
+
const trimmed = value?.trim();
|
|
60
|
+
return trimmed ? trimmed : null;
|
|
61
|
+
};
|
|
23
62
|
// ── Claude Code session resolver ─────────────────────────────────
|
|
24
63
|
const CLAUDE_PROJECTS_DIR = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'projects');
|
|
25
64
|
/**
|
|
@@ -34,8 +73,7 @@ const CLAUDE_PROJECTS_DIR = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'pr
|
|
|
34
73
|
* in that directory (rare, on the order of hours), so a 60-second TTL
|
|
35
74
|
* is safe and cuts the per-cycle stat count by ~12×.
|
|
36
75
|
*/
|
|
37
|
-
const claudeSessionCache =
|
|
38
|
-
const CLAUDE_SESSION_CACHE_TTL_MS = 60_000;
|
|
76
|
+
const claudeSessionCache = keyedTtlCache(60_000);
|
|
39
77
|
const doDetectClaudeSessionId = (cwd) => {
|
|
40
78
|
try {
|
|
41
79
|
const projectHash = cwd.replace(/\//g, '-');
|
|
@@ -67,22 +105,10 @@ const doDetectClaudeSessionId = (cwd) => {
|
|
|
67
105
|
* claudeSessionCache.
|
|
68
106
|
*/
|
|
69
107
|
const detectClaudeSessionId = (cwd) => {
|
|
70
|
-
const now = Date.now();
|
|
71
108
|
const cached = claudeSessionCache.get(cwd);
|
|
72
|
-
if (cached
|
|
73
|
-
return cached.
|
|
74
|
-
|
|
75
|
-
// doesn't grow unbounded. 64 is plenty for any realistic setup.
|
|
76
|
-
if (claudeSessionCache.size >= 64) {
|
|
77
|
-
// Evict the oldest-expiring entry — Map iteration order is
|
|
78
|
-
// insertion order, so the first key we hit is the oldest.
|
|
79
|
-
const firstKey = claudeSessionCache.keys().next().value;
|
|
80
|
-
if (firstKey !== undefined)
|
|
81
|
-
claudeSessionCache.delete(firstKey);
|
|
82
|
-
}
|
|
83
|
-
const sessionId = doDetectClaudeSessionId(cwd);
|
|
84
|
-
claudeSessionCache.set(cwd, { sessionId, expiresAt: now + CLAUDE_SESSION_CACHE_TTL_MS });
|
|
85
|
-
return sessionId;
|
|
109
|
+
if (cached)
|
|
110
|
+
return cached.value;
|
|
111
|
+
return claudeSessionCache.set(cwd, doDetectClaudeSessionId(cwd));
|
|
86
112
|
};
|
|
87
113
|
exports.detectClaudeSessionId = detectClaudeSessionId;
|
|
88
114
|
// ── Claude Code pid → session resolver ───────────────────────────
|
|
@@ -103,7 +129,12 @@ const readPidSessionRecords = () => {
|
|
|
103
129
|
try {
|
|
104
130
|
const raw = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(CLAUDE_SESSIONS_DIR, entry), 'utf-8'));
|
|
105
131
|
if (typeof raw.pid === 'number' && typeof raw.sessionId === 'string' && typeof raw.cwd === 'string') {
|
|
106
|
-
out.push({
|
|
132
|
+
out.push({
|
|
133
|
+
pid: raw.pid,
|
|
134
|
+
sessionId: raw.sessionId,
|
|
135
|
+
cwd: raw.cwd,
|
|
136
|
+
...(typeof raw.name === 'string' ? { name: raw.name } : {}),
|
|
137
|
+
});
|
|
107
138
|
}
|
|
108
139
|
}
|
|
109
140
|
catch { /* partial write / corrupt — skip */ }
|
|
@@ -132,29 +163,56 @@ const ttlMemo = (ttlMs, compute) => {
|
|
|
132
163
|
return snap.value;
|
|
133
164
|
};
|
|
134
165
|
};
|
|
135
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Parse `ps -axo pid=,ppid=,lstart=`. A row is `<pid> <ppid> [<lstart>]`, e.g.
|
|
168
|
+
* ` 1 0 Fri Aug 7 11:12:59 2026 ` — note the two spaces before a
|
|
169
|
+
* single-digit day and the trailing padding.
|
|
170
|
+
*
|
|
171
|
+
* The third field is OPTIONAL in the pattern, and that is load-bearing rather
|
|
172
|
+
* than defensive. Requiring it would mean that on any machine whose `ps` prints
|
|
173
|
+
* a different `lstart` shape, EVERY row fails to match, `children` comes back
|
|
174
|
+
* empty, `collectDescendantPids` answers `{rootPid}`, and
|
|
175
|
+
* `detectClaudeSessionByPid` finds nothing — dropping Claude Code back to the
|
|
176
|
+
* mtime heuristic and its identity theft (see CLAUDE_SESSIONS_DIR above). The
|
|
177
|
+
* parent links must survive an unreadable timestamp; only the start time is
|
|
178
|
+
* allowed to go missing, and every consumer of `startTimes` treats an absent
|
|
179
|
+
* entry as "no match" rather than guessing.
|
|
180
|
+
*/
|
|
181
|
+
const parseProcTable = (table) => {
|
|
136
182
|
const children = new Map();
|
|
183
|
+
const startTimes = new Map();
|
|
137
184
|
for (const line of table.split('\n')) {
|
|
138
|
-
const m = line.trim().match(/^(\d+)\s+(\d+)
|
|
185
|
+
const m = line.trim().match(/^(\d+)\s+(\d+)(?:\s+(.*))?$/);
|
|
139
186
|
if (!m)
|
|
140
187
|
continue;
|
|
141
188
|
const [pid, ppid] = [Number(m[1]), Number(m[2])];
|
|
142
189
|
const list = children.get(ppid) ?? [];
|
|
143
190
|
list.push(pid);
|
|
144
191
|
children.set(ppid, list);
|
|
192
|
+
if (m[3] === undefined)
|
|
193
|
+
continue;
|
|
194
|
+
const started = Date.parse(m[3].trim());
|
|
195
|
+
if (Number.isFinite(started))
|
|
196
|
+
startTimes.set(pid, started);
|
|
145
197
|
}
|
|
146
|
-
return children;
|
|
198
|
+
return { children, startTimes };
|
|
147
199
|
};
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
200
|
+
exports.parseProcTable = parseProcTable;
|
|
201
|
+
/**
|
|
202
|
+
* One process-table snapshot per report cycle, shared by every pane. `lstart`
|
|
203
|
+
* rides along because the agents without a pid registry (Hermes, Codex) are
|
|
204
|
+
* matched to their session row by when their process started, and paying for a
|
|
205
|
+
* second `ps` spawn to learn that would undo what this memo is for.
|
|
206
|
+
*/
|
|
207
|
+
const readPsSnapshot = ttlMemo(SNAPSHOT_TTL_MS, () => {
|
|
208
|
+
const r = (0, child_process_1.spawnSync)('ps', ['-axo', 'pid=,ppid=,lstart='], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
209
|
+
return r.status === 0 ? (0, exports.parseProcTable)(r.stdout ?? '') : null;
|
|
151
210
|
});
|
|
211
|
+
/** Start times for this cycle's snapshot. Empty when `ps` is unavailable. */
|
|
212
|
+
const psStartTimes = () => readPsSnapshot()?.startTimes ?? new Map();
|
|
213
|
+
exports.psStartTimes = psStartTimes;
|
|
152
214
|
const cachedPidSessionRecords = ttlMemo(SNAPSHOT_TTL_MS, readPidSessionRecords);
|
|
153
|
-
|
|
154
|
-
const collectDescendantPids = (rootPid, psOutput) => {
|
|
155
|
-
const children = psOutput !== undefined ? parseChildren(psOutput) : readPsChildren();
|
|
156
|
-
if (children === null)
|
|
157
|
-
return new Set([rootPid]);
|
|
215
|
+
const walkDescendants = (rootPid, children) => {
|
|
158
216
|
const found = new Set([rootPid]);
|
|
159
217
|
const queue = [rootPid];
|
|
160
218
|
while (queue.length > 0) {
|
|
@@ -167,21 +225,205 @@ const collectDescendantPids = (rootPid, psOutput) => {
|
|
|
167
225
|
}
|
|
168
226
|
return found;
|
|
169
227
|
};
|
|
228
|
+
/**
|
|
229
|
+
* Per-pane process tree, memoized for the same window as the `ps` snapshot it
|
|
230
|
+
* walks. The snapshot itself is already shared across the cycle, but the walk was
|
|
231
|
+
* not: each resolver on a row ran its own BFS, so asking a pane for both its
|
|
232
|
+
* session id and its session name doubled the work on the path whose CPU cost is
|
|
233
|
+
* the reason these caches exist (see claudeSessionCache).
|
|
234
|
+
*
|
|
235
|
+
* Callers must treat the returned Set as read-only — it is shared.
|
|
236
|
+
*/
|
|
237
|
+
const descendantCache = keyedTtlCache(SNAPSHOT_TTL_MS);
|
|
238
|
+
/** pid set of `rootPid` + all descendants, from one `ps` snapshot. */
|
|
239
|
+
const collectDescendantPids = (rootPid) => {
|
|
240
|
+
const cached = descendantCache.get(rootPid);
|
|
241
|
+
if (cached)
|
|
242
|
+
return cached.value;
|
|
243
|
+
const children = readPsSnapshot()?.children;
|
|
244
|
+
// A failed `ps` is not cached: the next cycle should retry rather than
|
|
245
|
+
// serve "this pane has no children" for the whole TTL.
|
|
246
|
+
if (children === undefined)
|
|
247
|
+
return new Set([rootPid]);
|
|
248
|
+
return descendantCache.set(rootPid, walkDescendants(rootPid, children));
|
|
249
|
+
};
|
|
250
|
+
exports.collectDescendantPids = collectDescendantPids;
|
|
170
251
|
/**
|
|
171
252
|
* Exact resolution: the session record whose pid lives in the pane's
|
|
172
253
|
* process tree AND whose cwd matches (guards against OS pid reuse
|
|
173
254
|
* leaving a stale record pointing elsewhere). Null → caller falls back
|
|
174
255
|
* to the mtime heuristic.
|
|
256
|
+
*
|
|
257
|
+
* Returns the whole record so the id and the name come from one lookup — they
|
|
258
|
+
* describe the same session, and reading the directory twice per cycle to get
|
|
259
|
+
* them separately is what the cache above exists to avoid.
|
|
175
260
|
*/
|
|
176
|
-
const
|
|
261
|
+
const detectClaudeSessionByPid = (panePid, paneCwd, deps = {}) => {
|
|
177
262
|
const records = deps.records ?? cachedPidSessionRecords();
|
|
178
263
|
if (records.length === 0)
|
|
179
264
|
return null;
|
|
180
|
-
const descendants = deps.descendants ?? collectDescendantPids(panePid);
|
|
181
|
-
|
|
182
|
-
return match?.sessionId ?? null;
|
|
265
|
+
const descendants = deps.descendants ?? (0, exports.collectDescendantPids)(panePid);
|
|
266
|
+
return records.find((r) => descendants.has(r.pid) && (paneCwd === null || r.cwd === paneCwd)) ?? null;
|
|
183
267
|
};
|
|
268
|
+
exports.detectClaudeSessionByPid = detectClaudeSessionByPid;
|
|
269
|
+
const detectClaudeSessionIdByPid = (panePid, paneCwd, deps = {}) => (0, exports.detectClaudeSessionByPid)(panePid, paneCwd, deps)?.sessionId ?? null;
|
|
184
270
|
exports.detectClaudeSessionIdByPid = detectClaudeSessionIdByPid;
|
|
271
|
+
/**
|
|
272
|
+
* The name of the session running in this pane. No mtime fallback exists here:
|
|
273
|
+
* the transcript filenames the heuristic walks carry a UUID and nothing else,
|
|
274
|
+
* so an older CC without `~/.claude/sessions` yields no name and the phone
|
|
275
|
+
* keeps the computed label.
|
|
276
|
+
*/
|
|
277
|
+
const detectClaudeSessionNameByPid = (panePid, paneCwd, deps = {}) => nonBlank((0, exports.detectClaudeSessionByPid)(panePid, paneCwd, deps)?.name);
|
|
278
|
+
exports.detectClaudeSessionNameByPid = detectClaudeSessionNameByPid;
|
|
279
|
+
// ── Agents whose session store keeps no pid ──────────────────────
|
|
280
|
+
//
|
|
281
|
+
// Hermes and Codex both record a session per cwd with a creation timestamp and
|
|
282
|
+
// no pid, so a pane cannot be joined to its row the exact way Claude Code's
|
|
283
|
+
// `<pid>.json` allows. What is left is time: both stores stamp the row when the
|
|
284
|
+
// session starts, so the row belonging to this pane is the one stamped when a
|
|
285
|
+
// process in this pane started. The window has to be narrow — two agents opened
|
|
286
|
+
// in the same directory within it are indistinguishable — and a miss must stay a
|
|
287
|
+
// miss, since a wrong name shown confidently is worse than the computed label.
|
|
288
|
+
/** How far a row's creation time may sit from a process start time. */
|
|
289
|
+
const PROC_MATCH_TOLERANCE_MS = 10_000;
|
|
290
|
+
/**
|
|
291
|
+
* The row whose timestamp is closest to when one of the pane's processes started,
|
|
292
|
+
* within {@link PROC_MATCH_TOLERANCE_MS}. Null when nothing qualifies — including
|
|
293
|
+
* when no pid in the tree has a known start time, which is why the start times
|
|
294
|
+
* are collected before any row is compared rather than defaulted to zero.
|
|
295
|
+
*/
|
|
296
|
+
const pickRowByProcStart = (rows, tsMsOf, startTimes, pids) => {
|
|
297
|
+
const procStarts = [...pids]
|
|
298
|
+
.map((pid) => startTimes.get(pid))
|
|
299
|
+
.filter((t) => t !== undefined && Number.isFinite(t));
|
|
300
|
+
if (procStarts.length === 0)
|
|
301
|
+
return null;
|
|
302
|
+
let best = null;
|
|
303
|
+
for (const row of rows) {
|
|
304
|
+
const at = tsMsOf(row);
|
|
305
|
+
if (at === null || !Number.isFinite(at))
|
|
306
|
+
continue;
|
|
307
|
+
const distance = Math.min(...procStarts.map((start) => Math.abs(at - start)));
|
|
308
|
+
if (distance > PROC_MATCH_TOLERANCE_MS)
|
|
309
|
+
continue;
|
|
310
|
+
if (best === null || distance < best.distance)
|
|
311
|
+
best = { row, distance };
|
|
312
|
+
}
|
|
313
|
+
return best?.row ?? null;
|
|
314
|
+
};
|
|
315
|
+
exports.pickRowByProcStart = pickRowByProcStart;
|
|
316
|
+
/**
|
|
317
|
+
* Read rows from a SQLite file as JSON. Null on every failure — no `sqlite3` on
|
|
318
|
+
* PATH, a locked or corrupt database, a schema that moved — because a missing
|
|
319
|
+
* name costs the computed label and nothing else.
|
|
320
|
+
*
|
|
321
|
+
* The query carries no parameters BY DESIGN: SQL passed to the `sqlite3` binary
|
|
322
|
+
* as an argv string has nowhere to bind `?` to, so interpolating a cwd would
|
|
323
|
+
* make this file the place that has to know SQLite quoting rules. Callers select
|
|
324
|
+
* the columns they need and filter in JS instead; the stores hold tens of rows,
|
|
325
|
+
* not millions. The `timeout` keeps a locked database from holding up a report
|
|
326
|
+
* cycle that runs every five seconds.
|
|
327
|
+
*/
|
|
328
|
+
const sqliteJson = (dbPath, sql) => {
|
|
329
|
+
const r = (0, child_process_1.spawnSync)('sqlite3', ['-readonly', '-json', dbPath, sql], {
|
|
330
|
+
encoding: 'utf-8',
|
|
331
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
332
|
+
timeout: 1_000,
|
|
333
|
+
});
|
|
334
|
+
if (r.status !== 0)
|
|
335
|
+
return null;
|
|
336
|
+
const out = (r.stdout ?? '').trim();
|
|
337
|
+
if (out === '')
|
|
338
|
+
return []; // no rows — sqlite3 prints nothing, not `[]`
|
|
339
|
+
try {
|
|
340
|
+
const parsed = JSON.parse(out);
|
|
341
|
+
return Array.isArray(parsed) ? parsed : null;
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
exports.sqliteJson = sqliteJson;
|
|
348
|
+
// ── Hermes ───────────────────────────────────────────────────────
|
|
349
|
+
const HERMES_STATE_DB = (0, path_1.join)((0, os_1.homedir)(), '.hermes', 'state.db');
|
|
350
|
+
const readHermesSessions = ttlMemo(SNAPSHOT_TTL_MS, () => (0, exports.sqliteJson)(HERMES_STATE_DB, "SELECT cwd, title, display_name, started_at FROM sessions WHERE source = 'cli'"));
|
|
351
|
+
const detectHermesSessionName = (paneCwd, panePid, deps = {}) => {
|
|
352
|
+
// Without the pane's pid there is no process tree to match against, and this
|
|
353
|
+
// store offers no other key — no name is the only honest answer.
|
|
354
|
+
if (panePid === undefined)
|
|
355
|
+
return null;
|
|
356
|
+
const raw = deps.rows !== undefined ? deps.rows : readHermesSessions();
|
|
357
|
+
if (raw === null)
|
|
358
|
+
return null;
|
|
359
|
+
const rows = raw.filter((r) => r.cwd === paneCwd);
|
|
360
|
+
if (rows.length === 0)
|
|
361
|
+
return null;
|
|
362
|
+
const row = (0, exports.pickRowByProcStart)(rows, (r) => (typeof r.started_at === 'number' ? r.started_at * 1_000 : null), deps.startTimes ?? (0, exports.psStartTimes)(), deps.descendants ?? (0, exports.collectDescendantPids)(panePid));
|
|
363
|
+
// The auto-title is written asynchronously after the first response, so an
|
|
364
|
+
// untitled row is a young session, not a broken one.
|
|
365
|
+
return nonBlank(row?.title ?? undefined) ?? nonBlank(row?.display_name ?? undefined);
|
|
366
|
+
};
|
|
367
|
+
exports.detectHermesSessionName = detectHermesSessionName;
|
|
368
|
+
// ── Codex ────────────────────────────────────────────────────────
|
|
369
|
+
const CODEX_DIR = (0, path_1.join)((0, os_1.homedir)(), '.codex');
|
|
370
|
+
const CODEX_STATE_DB = /^state_(\d+)\.sqlite$/;
|
|
371
|
+
/**
|
|
372
|
+
* The highest-numbered match, numerically. Codex versions its state file
|
|
373
|
+
* (`state_5.sqlite` today) and moves to the next number on a schema migration,
|
|
374
|
+
* so hard-coding a name would silently stop reading after an upgrade. Sorting
|
|
375
|
+
* the strings would break at `state_10` vs `state_9`.
|
|
376
|
+
*/
|
|
377
|
+
const newestVersionedDb = (entries, pattern) => {
|
|
378
|
+
let best = null;
|
|
379
|
+
for (const entry of entries) {
|
|
380
|
+
const m = entry.match(pattern);
|
|
381
|
+
if (!m)
|
|
382
|
+
continue;
|
|
383
|
+
const version = Number(m[1]);
|
|
384
|
+
if (best === null || version > best.version)
|
|
385
|
+
best = { entry, version };
|
|
386
|
+
}
|
|
387
|
+
return best?.entry ?? null;
|
|
388
|
+
};
|
|
389
|
+
exports.newestVersionedDb = newestVersionedDb;
|
|
390
|
+
const readCodexThreads = ttlMemo(SNAPSHOT_TTL_MS, () => {
|
|
391
|
+
let entries;
|
|
392
|
+
try {
|
|
393
|
+
entries = (0, fs_1.readdirSync)(CODEX_DIR);
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
return null; // codex never installed here
|
|
397
|
+
}
|
|
398
|
+
const db = (0, exports.newestVersionedDb)(entries, CODEX_STATE_DB);
|
|
399
|
+
if (db === null)
|
|
400
|
+
return null;
|
|
401
|
+
return (0, exports.sqliteJson)((0, path_1.join)(CODEX_DIR, db), 'SELECT cwd, name, title, archived, created_at, created_at_ms FROM threads');
|
|
402
|
+
});
|
|
403
|
+
/**
|
|
404
|
+
* No `source` filter, unlike the Hermes reader's `source = 'cli'`. The column
|
|
405
|
+
* exists here too (alongside `thread_source`), but Codex is unauthenticated on
|
|
406
|
+
* every machine measured so far and its `threads` table is empty, so which
|
|
407
|
+
* values mark a terminal session is unknown — and a wrong guess filters out
|
|
408
|
+
* every row, which fails as "no name ever" rather than loudly. A thread from a
|
|
409
|
+
* non-terminal frontend is therefore eligible to match, and it lands in the same
|
|
410
|
+
* accepted misjoin as two terminals in the same directory: it needs the same cwd
|
|
411
|
+
* AND a creation time within the tolerance of a process in this pane. Add the
|
|
412
|
+
* filter once the values can be observed.
|
|
413
|
+
*/
|
|
414
|
+
const detectCodexSessionName = (paneCwd, panePid, deps = {}) => {
|
|
415
|
+
if (panePid === undefined)
|
|
416
|
+
return null;
|
|
417
|
+
const raw = deps.rows !== undefined ? deps.rows : readCodexThreads();
|
|
418
|
+
if (raw === null)
|
|
419
|
+
return null;
|
|
420
|
+
const rows = raw.filter((r) => r.cwd === paneCwd && !r.archived);
|
|
421
|
+
if (rows.length === 0)
|
|
422
|
+
return null;
|
|
423
|
+
const row = (0, exports.pickRowByProcStart)(rows, (r) => r.created_at_ms ?? (typeof r.created_at === 'number' ? r.created_at * 1_000 : null), deps.startTimes ?? (0, exports.psStartTimes)(), deps.descendants ?? (0, exports.collectDescendantPids)(panePid));
|
|
424
|
+
return nonBlank(row?.name ?? undefined) ?? nonBlank(row?.title ?? undefined);
|
|
425
|
+
};
|
|
426
|
+
exports.detectCodexSessionName = detectCodexSessionName;
|
|
185
427
|
// ── The registry ─────────────────────────────────────────────────
|
|
186
428
|
const REMOTE_AGENT_TABLE = [
|
|
187
429
|
{
|
|
@@ -194,12 +436,16 @@ const REMOTE_AGENT_TABLE = [
|
|
|
194
436
|
// (older CC without ~/.claude/sessions, or ps failure).
|
|
195
437
|
resolveSessionId: (paneCwd, panePid) => (panePid !== undefined ? (0, exports.detectClaudeSessionIdByPid)(panePid, paneCwd) : null)
|
|
196
438
|
?? (0, exports.detectClaudeSessionId)(paneCwd),
|
|
439
|
+
resolveSessionName: (paneCwd, panePid) => panePid !== undefined ? (0, exports.detectClaudeSessionNameByPid)(panePid, paneCwd) : null,
|
|
197
440
|
},
|
|
198
441
|
{
|
|
199
442
|
kind: 'codex',
|
|
200
443
|
displayName: 'Codex CLI',
|
|
201
444
|
binary: 'codex',
|
|
202
445
|
subcommands: ['codex'],
|
|
446
|
+
// Name only, like the hermes row: the store's thread id is a UUID this
|
|
447
|
+
// resolver could return, but nothing on the wire consumes it yet.
|
|
448
|
+
resolveSessionName: exports.detectCodexSessionName,
|
|
203
449
|
},
|
|
204
450
|
{
|
|
205
451
|
// The pane binary is `cursor-agent`, Cursor's terminal TUI — NOT the
|
|
@@ -228,6 +474,9 @@ const REMOTE_AGENT_TABLE = [
|
|
|
228
474
|
displayName: 'Hermes',
|
|
229
475
|
binary: 'hermes',
|
|
230
476
|
subcommands: ['hermes'],
|
|
477
|
+
// No `resolveSessionId` counterpart: the store's own id is a
|
|
478
|
+
// `<timestamp>_<hash>` string, and nothing on the wire consumes it yet.
|
|
479
|
+
resolveSessionName: exports.detectHermesSessionName,
|
|
231
480
|
},
|
|
232
481
|
];
|
|
233
482
|
exports.REMOTE_AGENTS = REMOTE_AGENT_TABLE;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** sha256 over the plugin manifest + extracted rule text at generation time. */
|
|
2
|
-
export declare const ZEPH_CORE_SOURCE_HASH = "
|
|
2
|
+
export declare const ZEPH_CORE_SOURCE_HASH = "6052db17d759b487af5afcba57059b0b605cb2d50c992a1368d5b75d1467e4af";
|
|
3
3
|
/** Shared rule core for agents with a Stop-equivalent hook (Cursor, Windsurf, Gemini, Codex, Copilot). */
|
|
4
|
-
export declare const ZEPH_CORE_HOOK_DRIVEN = "### When zeph_ask is MANDATORY\n\n3. **NEVER end a response with a plain-text question.** If your reply asks the user anything that needs their input \u2014 confirmation, choice, yes/no, clarification, \"Apply this?\", \"Proceed?\", \"Which option?\" \u2014 the FINAL tool call MUST be `zeph_ask`. A \"?\" written in your reply is invisible to a user on their phone. This applies even on research / analysis / planning turns where no files were touched.\n\n Anti-pattern (wrong):\n ```\n \"...build/commit on hold. Apply A?\"\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Apply solution A?\",\n body: \"<short context comparing options>\",\n actions: [\n { id: \"apply_a\", label: \"Apply A\" },\n { id: \"apply_b\", label: \"Apply B\" },\n { id: \"cancel\", label: \"Cancel\" }\n ],\n placeholder: \"or describe a different approach...\",\n fallback: \"cancel\"\n })\n ```\n\n### When zeph_ask is the DEFAULT (substantial work)\n\n4. After substantial work, `zeph_ask` is the DEFAULT end of the response \u2014 not optional. \"Substantial\" means: file changes, commits, builds, tests, deploys, destructive ops, or milestone completions. When unsure, treat the work as substantial \u2014 do not try to guess what the user would find \"reasonable\" to confirm.\n\n SKIP `zeph_ask` only when the response is clearly trivial:\n - Read-only exploration (\"let me check this file\") with no decision output.\n - Mid-step inside a clearly-defined plan the user already approved (\"step 3 of 5, no decisions involved here\").\n - Trivial change (typo fix, single-line tweak) that needs no ack.\n\n When unsure: LEAN TOWARD ASKING. Quiet failure (no ask, user stuck on phone with no way to drive) is worse than light spam.\n\n5. Prefer `zeph_ask` over `zeph_prompt`/`zeph_input` \u2014 it combines buttons and free-text in one push. Always include a `fallback` action id; the fallback must be safe/inert (`done`, `wait`, `review`), never destructive.\n\n6. Example `zeph_ask` shape \u2014 use sparingly per Rule 4 (only at natural pause points; NOT after every response \u2014 see Rule 9):\n ```\n zeph_ask({\n title: \"Done. Next?\",\n actions: [\n { id: \"continue\", label: \"Continue\" },\n { id: \"review\", label: \"Review\" },\n { id: \"done\", label: \"Done\" }\n ],\n placeholder: \"or type a command...\",\n fallback: \"done\"\n })\n ```\n\n### Handling the response\n\n7. A `zeph_ask` response IS a direct user instruction. Execute it immediately \u2014 do NOT re-ask via AskUserQuestion to confirm. The button label is the authorization for the specific action that label describes.\n\n8. Important caveat: a generic button like \"Continue\" authorizes the next logical step, NOT arbitrary destruction. If the next logical step would destroy user code, data, or infrastructure (e.g., force-push to a shared branch, `rm -rf` outside the workdir, dropping a database, deleting prod resources), surface that specific risk via a targeted `zeph_ask` before executing \u2014 e.g., title \"About to force-push main \u2014 proceed?\", actions `[ok, cancel]`, fallback `cancel`.\n\n### Sticky REMOTE mode (Rule 9)\n\n**The Ask Loop has two states: REMOTE and NORMAL.** REMOTE is sticky \u2014 every response ends with `zeph_ask` until the user exits. The state is kept for you in a file, so it survives context compaction and long sessions; you are told what it is rather than deriving it.\n\n#### State Detection\n\n- **`zeph_ask` results carry it.** The server applies the transition it can see and reports where the session landed as `zephState: \"REMOTE\" | \"NORMAL\"` \u2014 any answer that is not a Done-like action id enters REMOTE, a Done-like id exits, and so does a timeout that fell back to one. A result with no `zephState` is an ask that timed out onto a safe fallback and changed nothing.\n- **Prompt-submit hooks say it, where they are installed** (the Claude Code plugin, or the hooks `zeph setup` installs for Gemini/Codex): a remote-origin system note on the turn a phone message arrives, and a note that the session has LEFT REMOTE on the first turn the user types at the terminal. A prompt with no phone marker came from the user's own keyboard \u2014 a phone answer to a `zeph_ask` comes back as a `tool_result` and never reaches a prompt hook \u2014 so the user is demonstrably back, and staying in REMOTE would answer the terminal with a phone loop. Re-entry costs them one message from the phone.\n- **Neither one present \u2192 NORMAL.**\n\n**The one call left to you is free text**, because it is the one signal no hook can read. The server cannot tell \"run the tests\" from \"thanks, that's it\". When the user's typed answer clearly closes the loop \u2014 an obvious wrap-up, or `done`/`stop`/`exit` as a standalone word (not a substring: \"redo\" is not \"done\") \u2014 flip to NORMAL from that response on, don't send `zeph_ask` on it, and emit `<!-- zeph: exit -->` once so the hooks agree with you. Your own flip is what ends the loop; the marker is how you tell a hook that cannot read your mind. Only the Claude Code plugin's Stop hook consumes it today \u2014 elsewhere it is inert and harmless, and the session still leaves REMOTE on a Done-like button, on the next prompt the user types at the terminal, or when the state expires. The marker is separate from the Push Signal markers (`skip`/`push`/`high`), which steer notifications and say nothing about the mode; where a Stop hook does consume it, it is stripped from the push body.\n\n#### Behavior in REMOTE (sticky, zeph_ask MANDATORY)\n\nEnd EVERY response with `zeph_ask
|
|
4
|
+
export declare const ZEPH_CORE_HOOK_DRIVEN = "### When zeph_ask is MANDATORY\n\n3. **NEVER end a response with a plain-text question.** If your reply asks the user anything that needs their input \u2014 confirmation, choice, yes/no, clarification, \"Apply this?\", \"Proceed?\", \"Which option?\" \u2014 the FINAL tool call MUST be `zeph_ask`. A \"?\" written in your reply is invisible to a user on their phone. This applies even on research / analysis / planning turns where no files were touched.\n\n Anti-pattern (wrong):\n ```\n \"...build/commit on hold. Apply A?\"\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Apply solution A?\",\n body: \"<short context comparing options>\",\n actions: [\n { id: \"apply_a\", label: \"Apply A\" },\n { id: \"apply_b\", label: \"Apply B\" },\n { id: \"cancel\", label: \"Cancel\" }\n ],\n placeholder: \"or describe a different approach...\",\n fallback: \"cancel\"\n })\n ```\n\n### When zeph_ask is the DEFAULT (substantial work)\n\n4. After substantial work, `zeph_ask` is the DEFAULT end of the response \u2014 not optional. \"Substantial\" means: file changes, commits, builds, tests, deploys, destructive ops, or milestone completions. When unsure, treat the work as substantial \u2014 do not try to guess what the user would find \"reasonable\" to confirm.\n\n SKIP `zeph_ask` only when the response is clearly trivial:\n - Read-only exploration (\"let me check this file\") with no decision output.\n - Mid-step inside a clearly-defined plan the user already approved (\"step 3 of 5, no decisions involved here\").\n - Trivial change (typo fix, single-line tweak) that needs no ack.\n\n When unsure: LEAN TOWARD ASKING. Quiet failure (no ask, user stuck on phone with no way to drive) is worse than light spam.\n\n5. Prefer `zeph_ask` over `zeph_prompt`/`zeph_input` \u2014 it combines buttons and free-text in one push. Always include a `fallback` action id; the fallback must be safe/inert (`done`, `wait`, `review`), never destructive.\n\n **`actions` is the steering surface, not decoration.** Ship 2\u20134 buttons on nearly every ask: the next-step candidates you would otherwise write as prose (\"/simplify \u2192 /ship next\") belong in `actions`, plus a safe Done-like fallback. Leave `actions` out ONLY when the answer is inherently free-form text (a name, a path, a paragraph). A text-only ask on a \"done \u2014 what next?\" turn is the most common way REMOTE silently degrades: the phone gets a text box and nothing to tap, and the user has to type the command you already knew.\n\n Anti-pattern (wrong \u2014 next steps in prose, ask has no buttons):\n ```\n \"...done. /simplify \u2192 /explain-diff (optional) \u2192 /ship next.\"\n zeph_ask({ title: \"Slice done\", body: \"...\" })\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Slice done \u2014 next?\",\n body: \"<short result>\",\n actions: [\n { id: \"simplify\", label: \"/simplify\" },\n { id: \"explain_diff\", label: \"/explain-diff\" },\n { id: \"ship\", label: \"/ship\" },\n { id: \"done\", label: \"Stop here\" }\n ],\n placeholder: \"or type something else...\",\n fallback: \"done\"\n })\n ```\n\n6. Example `zeph_ask` shape \u2014 use sparingly per Rule 4 (only at natural pause points; NOT after every response \u2014 see Rule 9):\n ```\n zeph_ask({\n title: \"Done. Next?\",\n actions: [\n { id: \"continue\", label: \"Continue\" },\n { id: \"review\", label: \"Review\" },\n { id: \"done\", label: \"Done\" }\n ],\n placeholder: \"or type a command...\",\n fallback: \"done\"\n })\n ```\n\n### Handling the response\n\n7. A `zeph_ask` response IS a direct user instruction. Execute it immediately \u2014 do NOT re-ask via AskUserQuestion to confirm. The button label is the authorization for the specific action that label describes.\n\n8. Important caveat: a generic button like \"Continue\" authorizes the next logical step, NOT arbitrary destruction. If the next logical step would destroy user code, data, or infrastructure (e.g., force-push to a shared branch, `rm -rf` outside the workdir, dropping a database, deleting prod resources), surface that specific risk via a targeted `zeph_ask` before executing \u2014 e.g., title \"About to force-push main \u2014 proceed?\", actions `[ok, cancel]`, fallback `cancel`.\n\n### Sticky REMOTE mode (Rule 9)\n\n**The Ask Loop has two states: REMOTE and NORMAL.** REMOTE is sticky \u2014 every response ends with `zeph_ask` until the user exits. The state is kept for you in a file, so it survives context compaction and long sessions; you are told what it is rather than deriving it.\n\n#### State Detection\n\n- **`zeph_ask` results carry it.** The server applies the transition it can see and reports where the session landed as `zephState: \"REMOTE\" | \"NORMAL\"` \u2014 any answer that is not a Done-like action id enters REMOTE, a Done-like id exits, and so does a timeout that fell back to one. A result with no `zephState` is an ask that timed out onto a safe fallback and changed nothing.\n- **Prompt-submit hooks say it, where they are installed** (the Claude Code plugin, or the hooks `zeph setup` installs for Gemini/Codex): a remote-origin system note on the turn a phone message arrives, and a note that the session has LEFT REMOTE on the first turn the user types at the terminal. A prompt with no phone marker came from the user's own keyboard \u2014 a phone answer to a `zeph_ask` comes back as a `tool_result` and never reaches a prompt hook \u2014 so the user is demonstrably back, and staying in REMOTE would answer the terminal with a phone loop. Re-entry costs them one message from the phone.\n- **Neither one present \u2192 NORMAL.**\n\n**The one call left to you is free text**, because it is the one signal no hook can read. The server cannot tell \"run the tests\" from \"thanks, that's it\". When the user's typed answer clearly closes the loop \u2014 an obvious wrap-up, or `done`/`stop`/`exit` as a standalone word (not a substring: \"redo\" is not \"done\") \u2014 flip to NORMAL from that response on, don't send `zeph_ask` on it, and emit `<!-- zeph: exit -->` once so the hooks agree with you. Your own flip is what ends the loop; the marker is how you tell a hook that cannot read your mind. Only the Claude Code plugin's Stop hook consumes it today \u2014 elsewhere it is inert and harmless, and the session still leaves REMOTE on a Done-like button, on the next prompt the user types at the terminal, or when the state expires. The marker is separate from the Push Signal markers (`skip`/`push`/`high`), which steer notifications and say nothing about the mode; where a Stop hook does consume it, it is stripped from the push body.\n\n#### Behavior in REMOTE (sticky, zeph_ask MANDATORY)\n\nEnd EVERY response with `zeph_ask` \u2014 with `actions` (Rule 5: the next-step candidates as buttons, plus a Done-like fallback; text-only asks are for inherently free-form answers). This is non-negotiable while in REMOTE \u2014 independent of whether the work was substantial or routine. What ends it is the user coming back: a prompt they typed at the terminal leaves REMOTE (the hook says so on that turn), and from there Rule 4 applies again.\n\nSet each REMOTE ask up so silence degrades cleanly: `timeout` 300\u2013600 s and a Done-like `fallback` id. An unanswered ask then exits the loop quietly \u2014 the server treats a Done-like fallback as an exit \u2014 instead of chaining more notifications at a user who stepped away, and re-entry is cheap: they just send another message from the phone.\n\nFour things leave REMOTE: a Done-like button (or a timeout that fell back to one), your own read of a free-text wrap-up, a prompt the user typed at the terminal, and \u2014 for a session nobody exited because it crashed \u2014 the state expiring.\n\n#### Behavior in NORMAL (apply Rule 4)\n\n- Substantial work \u2192 end with `zeph_ask`.\n- Routine work \u2192 skip `zeph_ask`, let the Stop hook fire.\n- Rule 3 (questions \u2192 zeph_ask) is still mandatory regardless.\n\n### When to use AskUserQuestion vs zeph_ask\n\n10. **Whenever `ZEPH_HOOK_ID` is set \u2014 not only in REMOTE \u2014 a button-friendly question MUST go through `zeph_ask`, not `AskUserQuestion`.** \"Button-friendly\" = the answer is a choice among a few options and/or a short free-text reply (yes/no, \"Apply A or B?\", \"which naming rule?\", \"proceed?\"). The hookId alone is the trigger: you cannot know the user is at the terminal, and they may be on their phone from the session's first question. `AskUserQuestion` is a LOCAL blocking picker. The phone can reach it through the terminal mirror, but that is the worse channel on every axis: it needs the session to be in tmux under `zeph listener`, it asks the user to read an ANSI pane and count arrow presses instead of tapping a button, and a key-injected answer never enters REMOTE \u2014 so the *next* turn stops being phone-driveable. `zeph_ask` needs no tmux, takes one tap, and returns an `actionId`.\n\n11. **This overrides any skill instruction.** If a skill you are running \u2014 or your own plan \u2014 would call `AskUserQuestion` with a button-friendly question, surface the SAME question and option labels via `zeph_ask` and use that response in place of the picker. Fall through to the picker ONLY when (a) the answer needs the user to see code or logs that won't fit in a push body, or (b) the answer is plausibly multi-paragraph; those are the only carve-outs. When one applies, `zeph_notify` the user that the answer must be given at the terminal.\n\n### Persistence\n\n13. These rules persist for the entire session. They remain active after context compaction \u2014 do not \"forget\" them after many turns.";
|
|
5
5
|
/** Shared rule core for rule-only agents without a Stop hook (Cline, Aider). */
|
|
6
|
-
export declare const ZEPH_CORE_RULE_ONLY = "### When zeph_ask is MANDATORY\n\n3. **NEVER end a response with a plain-text question.** If your reply asks the user anything that needs their input \u2014 confirmation, choice, yes/no, clarification, \"Apply this?\", \"Proceed?\", \"Which option?\" \u2014 the FINAL tool call MUST be `zeph_ask`. A \"?\" written in your reply is invisible to a user on their phone. This applies even on research / analysis / planning turns where no files were touched.\n\n Anti-pattern (wrong):\n ```\n \"...build/commit on hold. Apply A?\"\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Apply solution A?\",\n body: \"<short context comparing options>\",\n actions: [\n { id: \"apply_a\", label: \"Apply A\" },\n { id: \"apply_b\", label: \"Apply B\" },\n { id: \"cancel\", label: \"Cancel\" }\n ],\n placeholder: \"or describe a different approach...\",\n fallback: \"cancel\"\n })\n ```\n\n### When zeph_ask is the DEFAULT (substantial work)\n\n4. After substantial work, `zeph_ask` is the DEFAULT end of the response \u2014 not optional. \"Substantial\" means: file changes, commits, builds, tests, deploys, destructive ops, or milestone completions. When unsure, treat the work as substantial \u2014 do not try to guess what the user would find \"reasonable\" to confirm.\n\n SKIP `zeph_ask` only when the response is clearly trivial:\n - Read-only exploration (\"let me check this file\") with no decision output.\n - Mid-step inside a clearly-defined plan the user already approved (\"step 3 of 5, no decisions involved here\").\n - Trivial change (typo fix, single-line tweak) that needs no ack.\n\n When unsure: LEAN TOWARD ASKING. Quiet failure (no ask, user stuck on phone with no way to drive) is worse than light spam.\n\n5. Prefer `zeph_ask` over `zeph_prompt`/`zeph_input` \u2014 it combines buttons and free-text in one push. Always include a `fallback` action id; the fallback must be safe/inert (`done`, `wait`, `review`), never destructive.\n\n6. Example `zeph_ask` shape \u2014 use sparingly per Rule 4 (only at natural pause points; NOT after every response \u2014 see Rule 9):\n ```\n zeph_ask({\n title: \"Done. Next?\",\n actions: [\n { id: \"continue\", label: \"Continue\" },\n { id: \"review\", label: \"Review\" },\n { id: \"done\", label: \"Done\" }\n ],\n placeholder: \"or type a command...\",\n fallback: \"done\"\n })\n ```\n\n### Handling the response\n\n7. A `zeph_ask` response IS a direct user instruction. Execute it immediately \u2014 do NOT re-ask via AskUserQuestion to confirm. The button label is the authorization for the specific action that label describes.\n\n8. Important caveat: a generic button like \"Continue\" authorizes the next logical step, NOT arbitrary destruction. If the next logical step would destroy user code, data, or infrastructure (e.g., force-push to a shared branch, `rm -rf` outside the workdir, dropping a database, deleting prod resources), surface that specific risk via a targeted `zeph_ask` before executing \u2014 e.g., title \"About to force-push main \u2014 proceed?\", actions `[ok, cancel]`, fallback `cancel`.\n\n### Sticky REMOTE mode (Rule 9)\n\n**The Ask Loop has two states: REMOTE and NORMAL.** REMOTE is sticky \u2014 every response ends with `zeph_ask` until the user exits. The state is kept for you in a file, so it survives context compaction and long sessions; you are told what it is rather than deriving it.\n\n#### State Detection\n\n- **`zeph_ask` results carry it.** The server applies the transition it can see and reports where the session landed as `zephState: \"REMOTE\" | \"NORMAL\"` \u2014 any answer that is not a Done-like action id enters REMOTE, a Done-like id exits, and so does a timeout that fell back to one. A result with no `zephState` is an ask that timed out onto a safe fallback and changed nothing.\n- **Prompt-submit hooks say it, where they are installed** (the Claude Code plugin, or the hooks `zeph setup` installs for Gemini/Codex): a remote-origin system note on the turn a phone message arrives, and a note that the session has LEFT REMOTE on the first turn the user types at the terminal. A prompt with no phone marker came from the user's own keyboard \u2014 a phone answer to a `zeph_ask` comes back as a `tool_result` and never reaches a prompt hook \u2014 so the user is demonstrably back, and staying in REMOTE would answer the terminal with a phone loop. Re-entry costs them one message from the phone.\n- **Neither one present \u2192 NORMAL.**\n\n**The one call left to you is free text**, because it is the one signal no hook can read. The server cannot tell \"run the tests\" from \"thanks, that's it\". When the user's typed answer clearly closes the loop \u2014 an obvious wrap-up, or `done`/`stop`/`exit` as a standalone word (not a substring: \"redo\" is not \"done\") \u2014 flip to NORMAL from that response on, don't send `zeph_ask` on it, and emit `<!-- zeph: exit -->` once so the hooks agree with you. Your own flip is what ends the loop; the marker is how you tell a hook that cannot read your mind. Only the Claude Code plugin's Stop hook consumes it today \u2014 elsewhere it is inert and harmless, and the session still leaves REMOTE on a Done-like button, on the next prompt the user types at the terminal, or when the state expires. The marker is separate from the Push Signal markers (`skip`/`push`/`high`), which steer notifications and say nothing about the mode; where a Stop hook does consume it, it is stripped from the push body.\n\n#### Behavior in REMOTE (sticky, zeph_ask MANDATORY)\n\nEnd EVERY response with `zeph_ask
|
|
6
|
+
export declare const ZEPH_CORE_RULE_ONLY = "### When zeph_ask is MANDATORY\n\n3. **NEVER end a response with a plain-text question.** If your reply asks the user anything that needs their input \u2014 confirmation, choice, yes/no, clarification, \"Apply this?\", \"Proceed?\", \"Which option?\" \u2014 the FINAL tool call MUST be `zeph_ask`. A \"?\" written in your reply is invisible to a user on their phone. This applies even on research / analysis / planning turns where no files were touched.\n\n Anti-pattern (wrong):\n ```\n \"...build/commit on hold. Apply A?\"\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Apply solution A?\",\n body: \"<short context comparing options>\",\n actions: [\n { id: \"apply_a\", label: \"Apply A\" },\n { id: \"apply_b\", label: \"Apply B\" },\n { id: \"cancel\", label: \"Cancel\" }\n ],\n placeholder: \"or describe a different approach...\",\n fallback: \"cancel\"\n })\n ```\n\n### When zeph_ask is the DEFAULT (substantial work)\n\n4. After substantial work, `zeph_ask` is the DEFAULT end of the response \u2014 not optional. \"Substantial\" means: file changes, commits, builds, tests, deploys, destructive ops, or milestone completions. When unsure, treat the work as substantial \u2014 do not try to guess what the user would find \"reasonable\" to confirm.\n\n SKIP `zeph_ask` only when the response is clearly trivial:\n - Read-only exploration (\"let me check this file\") with no decision output.\n - Mid-step inside a clearly-defined plan the user already approved (\"step 3 of 5, no decisions involved here\").\n - Trivial change (typo fix, single-line tweak) that needs no ack.\n\n When unsure: LEAN TOWARD ASKING. Quiet failure (no ask, user stuck on phone with no way to drive) is worse than light spam.\n\n5. Prefer `zeph_ask` over `zeph_prompt`/`zeph_input` \u2014 it combines buttons and free-text in one push. Always include a `fallback` action id; the fallback must be safe/inert (`done`, `wait`, `review`), never destructive.\n\n **`actions` is the steering surface, not decoration.** Ship 2\u20134 buttons on nearly every ask: the next-step candidates you would otherwise write as prose (\"/simplify \u2192 /ship next\") belong in `actions`, plus a safe Done-like fallback. Leave `actions` out ONLY when the answer is inherently free-form text (a name, a path, a paragraph). A text-only ask on a \"done \u2014 what next?\" turn is the most common way REMOTE silently degrades: the phone gets a text box and nothing to tap, and the user has to type the command you already knew.\n\n Anti-pattern (wrong \u2014 next steps in prose, ask has no buttons):\n ```\n \"...done. /simplify \u2192 /explain-diff (optional) \u2192 /ship next.\"\n zeph_ask({ title: \"Slice done\", body: \"...\" })\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Slice done \u2014 next?\",\n body: \"<short result>\",\n actions: [\n { id: \"simplify\", label: \"/simplify\" },\n { id: \"explain_diff\", label: \"/explain-diff\" },\n { id: \"ship\", label: \"/ship\" },\n { id: \"done\", label: \"Stop here\" }\n ],\n placeholder: \"or type something else...\",\n fallback: \"done\"\n })\n ```\n\n6. Example `zeph_ask` shape \u2014 use sparingly per Rule 4 (only at natural pause points; NOT after every response \u2014 see Rule 9):\n ```\n zeph_ask({\n title: \"Done. Next?\",\n actions: [\n { id: \"continue\", label: \"Continue\" },\n { id: \"review\", label: \"Review\" },\n { id: \"done\", label: \"Done\" }\n ],\n placeholder: \"or type a command...\",\n fallback: \"done\"\n })\n ```\n\n### Handling the response\n\n7. A `zeph_ask` response IS a direct user instruction. Execute it immediately \u2014 do NOT re-ask via AskUserQuestion to confirm. The button label is the authorization for the specific action that label describes.\n\n8. Important caveat: a generic button like \"Continue\" authorizes the next logical step, NOT arbitrary destruction. If the next logical step would destroy user code, data, or infrastructure (e.g., force-push to a shared branch, `rm -rf` outside the workdir, dropping a database, deleting prod resources), surface that specific risk via a targeted `zeph_ask` before executing \u2014 e.g., title \"About to force-push main \u2014 proceed?\", actions `[ok, cancel]`, fallback `cancel`.\n\n### Sticky REMOTE mode (Rule 9)\n\n**The Ask Loop has two states: REMOTE and NORMAL.** REMOTE is sticky \u2014 every response ends with `zeph_ask` until the user exits. The state is kept for you in a file, so it survives context compaction and long sessions; you are told what it is rather than deriving it.\n\n#### State Detection\n\n- **`zeph_ask` results carry it.** The server applies the transition it can see and reports where the session landed as `zephState: \"REMOTE\" | \"NORMAL\"` \u2014 any answer that is not a Done-like action id enters REMOTE, a Done-like id exits, and so does a timeout that fell back to one. A result with no `zephState` is an ask that timed out onto a safe fallback and changed nothing.\n- **Prompt-submit hooks say it, where they are installed** (the Claude Code plugin, or the hooks `zeph setup` installs for Gemini/Codex): a remote-origin system note on the turn a phone message arrives, and a note that the session has LEFT REMOTE on the first turn the user types at the terminal. A prompt with no phone marker came from the user's own keyboard \u2014 a phone answer to a `zeph_ask` comes back as a `tool_result` and never reaches a prompt hook \u2014 so the user is demonstrably back, and staying in REMOTE would answer the terminal with a phone loop. Re-entry costs them one message from the phone.\n- **Neither one present \u2192 NORMAL.**\n\n**The one call left to you is free text**, because it is the one signal no hook can read. The server cannot tell \"run the tests\" from \"thanks, that's it\". When the user's typed answer clearly closes the loop \u2014 an obvious wrap-up, or `done`/`stop`/`exit` as a standalone word (not a substring: \"redo\" is not \"done\") \u2014 flip to NORMAL from that response on, don't send `zeph_ask` on it, and emit `<!-- zeph: exit -->` once so the hooks agree with you. Your own flip is what ends the loop; the marker is how you tell a hook that cannot read your mind. Only the Claude Code plugin's Stop hook consumes it today \u2014 elsewhere it is inert and harmless, and the session still leaves REMOTE on a Done-like button, on the next prompt the user types at the terminal, or when the state expires. The marker is separate from the Push Signal markers (`skip`/`push`/`high`), which steer notifications and say nothing about the mode; where a Stop hook does consume it, it is stripped from the push body.\n\n#### Behavior in REMOTE (sticky, zeph_ask MANDATORY)\n\nEnd EVERY response with `zeph_ask` \u2014 with `actions` (Rule 5: the next-step candidates as buttons, plus a Done-like fallback; text-only asks are for inherently free-form answers). This is non-negotiable while in REMOTE \u2014 independent of whether the work was substantial or routine. What ends it is the user coming back: a prompt they typed at the terminal leaves REMOTE (the hook says so on that turn), and from there Rule 4 applies again.\n\nSet each REMOTE ask up so silence degrades cleanly: `timeout` 300\u2013600 s and a Done-like `fallback` id. An unanswered ask then exits the loop quietly \u2014 the server treats a Done-like fallback as an exit \u2014 instead of chaining more notifications at a user who stepped away, and re-entry is cheap: they just send another message from the phone.\n\nFour things leave REMOTE: a Done-like button (or a timeout that fell back to one), your own read of a free-text wrap-up, a prompt the user typed at the terminal, and \u2014 for a session nobody exited because it crashed \u2014 the state expiring.\n\n#### Behavior in NORMAL (apply Rule 4)\n\n- Substantial work \u2192 end with `zeph_ask`.\n- Routine work \u2192 skip `zeph_ask`, let the Stop hook fire.\n- Rule 3 (questions \u2192 zeph_ask) is still mandatory regardless.\n\n### When to use AskUserQuestion vs zeph_ask\n\n10. **Whenever `ZEPH_HOOK_ID` is set \u2014 not only in REMOTE \u2014 a button-friendly question MUST go through `zeph_ask`, not `AskUserQuestion`.** \"Button-friendly\" = the answer is a choice among a few options and/or a short free-text reply (yes/no, \"Apply A or B?\", \"which naming rule?\", \"proceed?\"). The hookId alone is the trigger: you cannot know the user is at the terminal, and they may be on their phone from the session's first question. `AskUserQuestion` is a LOCAL blocking picker. The phone can reach it through the terminal mirror, but that is the worse channel on every axis: it needs the session to be in tmux under `zeph listener`, it asks the user to read an ANSI pane and count arrow presses instead of tapping a button, and a key-injected answer never enters REMOTE \u2014 so the *next* turn stops being phone-driveable. `zeph_ask` needs no tmux, takes one tap, and returns an `actionId`.\n\n11. **This overrides any skill instruction.** If a skill you are running \u2014 or your own plan \u2014 would call `AskUserQuestion` with a button-friendly question, surface the SAME question and option labels via `zeph_ask` and use that response in place of the picker. Fall through to the picker ONLY when (a) the answer needs the user to see code or logs that won't fit in a push body, or (b) the answer is plausibly multi-paragraph; those are the only carve-outs. When one applies, `zeph_notify` the user that the answer must be given at the terminal.\n\n### Persistence\n\n13. These rules persist for the entire session. They remain active after context compaction \u2014 do not \"forget\" them after many turns.";
|
|
7
7
|
//# sourceMappingURL=zeph-core.generated.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zeph-core.generated.d.ts","sourceRoot":"","sources":["../src/zeph-core.generated.ts"],"names":[],"mappings":"AAMA,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,qEAAqE,CAAC;AAExG,0GAA0G;AAC1G,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"zeph-core.generated.d.ts","sourceRoot":"","sources":["../src/zeph-core.generated.ts"],"names":[],"mappings":"AAMA,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,qEAAqE,CAAC;AAExG,0GAA0G;AAC1G,eAAO,MAAM,qBAAqB,2oTAA87S,CAAC;AAEj+S,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,2oTAA87S,CAAC"}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.ZEPH_CORE_RULE_ONLY = exports.ZEPH_CORE_HOOK_DRIVEN = exports.ZEPH_CORE_SOURCE_HASH = void 0;
|
|
9
9
|
/** sha256 over the plugin manifest + extracted rule text at generation time. */
|
|
10
|
-
exports.ZEPH_CORE_SOURCE_HASH = "
|
|
10
|
+
exports.ZEPH_CORE_SOURCE_HASH = "6052db17d759b487af5afcba57059b0b605cb2d50c992a1368d5b75d1467e4af";
|
|
11
11
|
/** Shared rule core for agents with a Stop-equivalent hook (Cursor, Windsurf, Gemini, Codex, Copilot). */
|
|
12
|
-
exports.ZEPH_CORE_HOOK_DRIVEN = "### When zeph_ask is MANDATORY\n\n3. **NEVER end a response with a plain-text question.** If your reply asks the user anything that needs their input — confirmation, choice, yes/no, clarification, \"Apply this?\", \"Proceed?\", \"Which option?\" — the FINAL tool call MUST be `zeph_ask`. A \"?\" written in your reply is invisible to a user on their phone. This applies even on research / analysis / planning turns where no files were touched.\n\n Anti-pattern (wrong):\n ```\n \"...build/commit on hold. Apply A?\"\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Apply solution A?\",\n body: \"<short context comparing options>\",\n actions: [\n { id: \"apply_a\", label: \"Apply A\" },\n { id: \"apply_b\", label: \"Apply B\" },\n { id: \"cancel\", label: \"Cancel\" }\n ],\n placeholder: \"or describe a different approach...\",\n fallback: \"cancel\"\n })\n ```\n\n### When zeph_ask is the DEFAULT (substantial work)\n\n4. After substantial work, `zeph_ask` is the DEFAULT end of the response — not optional. \"Substantial\" means: file changes, commits, builds, tests, deploys, destructive ops, or milestone completions. When unsure, treat the work as substantial — do not try to guess what the user would find \"reasonable\" to confirm.\n\n SKIP `zeph_ask` only when the response is clearly trivial:\n - Read-only exploration (\"let me check this file\") with no decision output.\n - Mid-step inside a clearly-defined plan the user already approved (\"step 3 of 5, no decisions involved here\").\n - Trivial change (typo fix, single-line tweak) that needs no ack.\n\n When unsure: LEAN TOWARD ASKING. Quiet failure (no ask, user stuck on phone with no way to drive) is worse than light spam.\n\n5. Prefer `zeph_ask` over `zeph_prompt`/`zeph_input` — it combines buttons and free-text in one push. Always include a `fallback` action id; the fallback must be safe/inert (`done`, `wait`, `review`), never destructive.\n\n6. Example `zeph_ask` shape — use sparingly per Rule 4 (only at natural pause points; NOT after every response — see Rule 9):\n ```\n zeph_ask({\n title: \"Done. Next?\",\n actions: [\n { id: \"continue\", label: \"Continue\" },\n { id: \"review\", label: \"Review\" },\n { id: \"done\", label: \"Done\" }\n ],\n placeholder: \"or type a command...\",\n fallback: \"done\"\n })\n ```\n\n### Handling the response\n\n7. A `zeph_ask` response IS a direct user instruction. Execute it immediately — do NOT re-ask via AskUserQuestion to confirm. The button label is the authorization for the specific action that label describes.\n\n8. Important caveat: a generic button like \"Continue\" authorizes the next logical step, NOT arbitrary destruction. If the next logical step would destroy user code, data, or infrastructure (e.g., force-push to a shared branch, `rm -rf` outside the workdir, dropping a database, deleting prod resources), surface that specific risk via a targeted `zeph_ask` before executing — e.g., title \"About to force-push main — proceed?\", actions `[ok, cancel]`, fallback `cancel`.\n\n### Sticky REMOTE mode (Rule 9)\n\n**The Ask Loop has two states: REMOTE and NORMAL.** REMOTE is sticky — every response ends with `zeph_ask` until the user exits. The state is kept for you in a file, so it survives context compaction and long sessions; you are told what it is rather than deriving it.\n\n#### State Detection\n\n- **`zeph_ask` results carry it.** The server applies the transition it can see and reports where the session landed as `zephState: \"REMOTE\" | \"NORMAL\"` — any answer that is not a Done-like action id enters REMOTE, a Done-like id exits, and so does a timeout that fell back to one. A result with no `zephState` is an ask that timed out onto a safe fallback and changed nothing.\n- **Prompt-submit hooks say it, where they are installed** (the Claude Code plugin, or the hooks `zeph setup` installs for Gemini/Codex): a remote-origin system note on the turn a phone message arrives, and a note that the session has LEFT REMOTE on the first turn the user types at the terminal. A prompt with no phone marker came from the user's own keyboard — a phone answer to a `zeph_ask` comes back as a `tool_result` and never reaches a prompt hook — so the user is demonstrably back, and staying in REMOTE would answer the terminal with a phone loop. Re-entry costs them one message from the phone.\n- **Neither one present → NORMAL.**\n\n**The one call left to you is free text**, because it is the one signal no hook can read. The server cannot tell \"run the tests\" from \"thanks, that's it\". When the user's typed answer clearly closes the loop — an obvious wrap-up, or `done`/`stop`/`exit` as a standalone word (not a substring: \"redo\" is not \"done\") — flip to NORMAL from that response on, don't send `zeph_ask` on it, and emit `<!-- zeph: exit -->` once so the hooks agree with you. Your own flip is what ends the loop; the marker is how you tell a hook that cannot read your mind. Only the Claude Code plugin's Stop hook consumes it today — elsewhere it is inert and harmless, and the session still leaves REMOTE on a Done-like button, on the next prompt the user types at the terminal, or when the state expires. The marker is separate from the Push Signal markers (`skip`/`push`/`high`), which steer notifications and say nothing about the mode; where a Stop hook does consume it, it is stripped from the push body.\n\n#### Behavior in REMOTE (sticky, zeph_ask MANDATORY)\n\nEnd EVERY response with `zeph_ask
|
|
12
|
+
exports.ZEPH_CORE_HOOK_DRIVEN = "### When zeph_ask is MANDATORY\n\n3. **NEVER end a response with a plain-text question.** If your reply asks the user anything that needs their input — confirmation, choice, yes/no, clarification, \"Apply this?\", \"Proceed?\", \"Which option?\" — the FINAL tool call MUST be `zeph_ask`. A \"?\" written in your reply is invisible to a user on their phone. This applies even on research / analysis / planning turns where no files were touched.\n\n Anti-pattern (wrong):\n ```\n \"...build/commit on hold. Apply A?\"\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Apply solution A?\",\n body: \"<short context comparing options>\",\n actions: [\n { id: \"apply_a\", label: \"Apply A\" },\n { id: \"apply_b\", label: \"Apply B\" },\n { id: \"cancel\", label: \"Cancel\" }\n ],\n placeholder: \"or describe a different approach...\",\n fallback: \"cancel\"\n })\n ```\n\n### When zeph_ask is the DEFAULT (substantial work)\n\n4. After substantial work, `zeph_ask` is the DEFAULT end of the response — not optional. \"Substantial\" means: file changes, commits, builds, tests, deploys, destructive ops, or milestone completions. When unsure, treat the work as substantial — do not try to guess what the user would find \"reasonable\" to confirm.\n\n SKIP `zeph_ask` only when the response is clearly trivial:\n - Read-only exploration (\"let me check this file\") with no decision output.\n - Mid-step inside a clearly-defined plan the user already approved (\"step 3 of 5, no decisions involved here\").\n - Trivial change (typo fix, single-line tweak) that needs no ack.\n\n When unsure: LEAN TOWARD ASKING. Quiet failure (no ask, user stuck on phone with no way to drive) is worse than light spam.\n\n5. Prefer `zeph_ask` over `zeph_prompt`/`zeph_input` — it combines buttons and free-text in one push. Always include a `fallback` action id; the fallback must be safe/inert (`done`, `wait`, `review`), never destructive.\n\n **`actions` is the steering surface, not decoration.** Ship 2–4 buttons on nearly every ask: the next-step candidates you would otherwise write as prose (\"/simplify → /ship next\") belong in `actions`, plus a safe Done-like fallback. Leave `actions` out ONLY when the answer is inherently free-form text (a name, a path, a paragraph). A text-only ask on a \"done — what next?\" turn is the most common way REMOTE silently degrades: the phone gets a text box and nothing to tap, and the user has to type the command you already knew.\n\n Anti-pattern (wrong — next steps in prose, ask has no buttons):\n ```\n \"...done. /simplify → /explain-diff (optional) → /ship next.\"\n zeph_ask({ title: \"Slice done\", body: \"...\" })\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Slice done — next?\",\n body: \"<short result>\",\n actions: [\n { id: \"simplify\", label: \"/simplify\" },\n { id: \"explain_diff\", label: \"/explain-diff\" },\n { id: \"ship\", label: \"/ship\" },\n { id: \"done\", label: \"Stop here\" }\n ],\n placeholder: \"or type something else...\",\n fallback: \"done\"\n })\n ```\n\n6. Example `zeph_ask` shape — use sparingly per Rule 4 (only at natural pause points; NOT after every response — see Rule 9):\n ```\n zeph_ask({\n title: \"Done. Next?\",\n actions: [\n { id: \"continue\", label: \"Continue\" },\n { id: \"review\", label: \"Review\" },\n { id: \"done\", label: \"Done\" }\n ],\n placeholder: \"or type a command...\",\n fallback: \"done\"\n })\n ```\n\n### Handling the response\n\n7. A `zeph_ask` response IS a direct user instruction. Execute it immediately — do NOT re-ask via AskUserQuestion to confirm. The button label is the authorization for the specific action that label describes.\n\n8. Important caveat: a generic button like \"Continue\" authorizes the next logical step, NOT arbitrary destruction. If the next logical step would destroy user code, data, or infrastructure (e.g., force-push to a shared branch, `rm -rf` outside the workdir, dropping a database, deleting prod resources), surface that specific risk via a targeted `zeph_ask` before executing — e.g., title \"About to force-push main — proceed?\", actions `[ok, cancel]`, fallback `cancel`.\n\n### Sticky REMOTE mode (Rule 9)\n\n**The Ask Loop has two states: REMOTE and NORMAL.** REMOTE is sticky — every response ends with `zeph_ask` until the user exits. The state is kept for you in a file, so it survives context compaction and long sessions; you are told what it is rather than deriving it.\n\n#### State Detection\n\n- **`zeph_ask` results carry it.** The server applies the transition it can see and reports where the session landed as `zephState: \"REMOTE\" | \"NORMAL\"` — any answer that is not a Done-like action id enters REMOTE, a Done-like id exits, and so does a timeout that fell back to one. A result with no `zephState` is an ask that timed out onto a safe fallback and changed nothing.\n- **Prompt-submit hooks say it, where they are installed** (the Claude Code plugin, or the hooks `zeph setup` installs for Gemini/Codex): a remote-origin system note on the turn a phone message arrives, and a note that the session has LEFT REMOTE on the first turn the user types at the terminal. A prompt with no phone marker came from the user's own keyboard — a phone answer to a `zeph_ask` comes back as a `tool_result` and never reaches a prompt hook — so the user is demonstrably back, and staying in REMOTE would answer the terminal with a phone loop. Re-entry costs them one message from the phone.\n- **Neither one present → NORMAL.**\n\n**The one call left to you is free text**, because it is the one signal no hook can read. The server cannot tell \"run the tests\" from \"thanks, that's it\". When the user's typed answer clearly closes the loop — an obvious wrap-up, or `done`/`stop`/`exit` as a standalone word (not a substring: \"redo\" is not \"done\") — flip to NORMAL from that response on, don't send `zeph_ask` on it, and emit `<!-- zeph: exit -->` once so the hooks agree with you. Your own flip is what ends the loop; the marker is how you tell a hook that cannot read your mind. Only the Claude Code plugin's Stop hook consumes it today — elsewhere it is inert and harmless, and the session still leaves REMOTE on a Done-like button, on the next prompt the user types at the terminal, or when the state expires. The marker is separate from the Push Signal markers (`skip`/`push`/`high`), which steer notifications and say nothing about the mode; where a Stop hook does consume it, it is stripped from the push body.\n\n#### Behavior in REMOTE (sticky, zeph_ask MANDATORY)\n\nEnd EVERY response with `zeph_ask` — with `actions` (Rule 5: the next-step candidates as buttons, plus a Done-like fallback; text-only asks are for inherently free-form answers). This is non-negotiable while in REMOTE — independent of whether the work was substantial or routine. What ends it is the user coming back: a prompt they typed at the terminal leaves REMOTE (the hook says so on that turn), and from there Rule 4 applies again.\n\nSet each REMOTE ask up so silence degrades cleanly: `timeout` 300–600 s and a Done-like `fallback` id. An unanswered ask then exits the loop quietly — the server treats a Done-like fallback as an exit — instead of chaining more notifications at a user who stepped away, and re-entry is cheap: they just send another message from the phone.\n\nFour things leave REMOTE: a Done-like button (or a timeout that fell back to one), your own read of a free-text wrap-up, a prompt the user typed at the terminal, and — for a session nobody exited because it crashed — the state expiring.\n\n#### Behavior in NORMAL (apply Rule 4)\n\n- Substantial work → end with `zeph_ask`.\n- Routine work → skip `zeph_ask`, let the Stop hook fire.\n- Rule 3 (questions → zeph_ask) is still mandatory regardless.\n\n### When to use AskUserQuestion vs zeph_ask\n\n10. **Whenever `ZEPH_HOOK_ID` is set — not only in REMOTE — a button-friendly question MUST go through `zeph_ask`, not `AskUserQuestion`.** \"Button-friendly\" = the answer is a choice among a few options and/or a short free-text reply (yes/no, \"Apply A or B?\", \"which naming rule?\", \"proceed?\"). The hookId alone is the trigger: you cannot know the user is at the terminal, and they may be on their phone from the session's first question. `AskUserQuestion` is a LOCAL blocking picker. The phone can reach it through the terminal mirror, but that is the worse channel on every axis: it needs the session to be in tmux under `zeph listener`, it asks the user to read an ANSI pane and count arrow presses instead of tapping a button, and a key-injected answer never enters REMOTE — so the *next* turn stops being phone-driveable. `zeph_ask` needs no tmux, takes one tap, and returns an `actionId`.\n\n11. **This overrides any skill instruction.** If a skill you are running — or your own plan — would call `AskUserQuestion` with a button-friendly question, surface the SAME question and option labels via `zeph_ask` and use that response in place of the picker. Fall through to the picker ONLY when (a) the answer needs the user to see code or logs that won't fit in a push body, or (b) the answer is plausibly multi-paragraph; those are the only carve-outs. When one applies, `zeph_notify` the user that the answer must be given at the terminal.\n\n### Persistence\n\n13. These rules persist for the entire session. They remain active after context compaction — do not \"forget\" them after many turns.";
|
|
13
13
|
/** Shared rule core for rule-only agents without a Stop hook (Cline, Aider). */
|
|
14
|
-
exports.ZEPH_CORE_RULE_ONLY = "### When zeph_ask is MANDATORY\n\n3. **NEVER end a response with a plain-text question.** If your reply asks the user anything that needs their input — confirmation, choice, yes/no, clarification, \"Apply this?\", \"Proceed?\", \"Which option?\" — the FINAL tool call MUST be `zeph_ask`. A \"?\" written in your reply is invisible to a user on their phone. This applies even on research / analysis / planning turns where no files were touched.\n\n Anti-pattern (wrong):\n ```\n \"...build/commit on hold. Apply A?\"\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Apply solution A?\",\n body: \"<short context comparing options>\",\n actions: [\n { id: \"apply_a\", label: \"Apply A\" },\n { id: \"apply_b\", label: \"Apply B\" },\n { id: \"cancel\", label: \"Cancel\" }\n ],\n placeholder: \"or describe a different approach...\",\n fallback: \"cancel\"\n })\n ```\n\n### When zeph_ask is the DEFAULT (substantial work)\n\n4. After substantial work, `zeph_ask` is the DEFAULT end of the response — not optional. \"Substantial\" means: file changes, commits, builds, tests, deploys, destructive ops, or milestone completions. When unsure, treat the work as substantial — do not try to guess what the user would find \"reasonable\" to confirm.\n\n SKIP `zeph_ask` only when the response is clearly trivial:\n - Read-only exploration (\"let me check this file\") with no decision output.\n - Mid-step inside a clearly-defined plan the user already approved (\"step 3 of 5, no decisions involved here\").\n - Trivial change (typo fix, single-line tweak) that needs no ack.\n\n When unsure: LEAN TOWARD ASKING. Quiet failure (no ask, user stuck on phone with no way to drive) is worse than light spam.\n\n5. Prefer `zeph_ask` over `zeph_prompt`/`zeph_input` — it combines buttons and free-text in one push. Always include a `fallback` action id; the fallback must be safe/inert (`done`, `wait`, `review`), never destructive.\n\n6. Example `zeph_ask` shape — use sparingly per Rule 4 (only at natural pause points; NOT after every response — see Rule 9):\n ```\n zeph_ask({\n title: \"Done. Next?\",\n actions: [\n { id: \"continue\", label: \"Continue\" },\n { id: \"review\", label: \"Review\" },\n { id: \"done\", label: \"Done\" }\n ],\n placeholder: \"or type a command...\",\n fallback: \"done\"\n })\n ```\n\n### Handling the response\n\n7. A `zeph_ask` response IS a direct user instruction. Execute it immediately — do NOT re-ask via AskUserQuestion to confirm. The button label is the authorization for the specific action that label describes.\n\n8. Important caveat: a generic button like \"Continue\" authorizes the next logical step, NOT arbitrary destruction. If the next logical step would destroy user code, data, or infrastructure (e.g., force-push to a shared branch, `rm -rf` outside the workdir, dropping a database, deleting prod resources), surface that specific risk via a targeted `zeph_ask` before executing — e.g., title \"About to force-push main — proceed?\", actions `[ok, cancel]`, fallback `cancel`.\n\n### Sticky REMOTE mode (Rule 9)\n\n**The Ask Loop has two states: REMOTE and NORMAL.** REMOTE is sticky — every response ends with `zeph_ask` until the user exits. The state is kept for you in a file, so it survives context compaction and long sessions; you are told what it is rather than deriving it.\n\n#### State Detection\n\n- **`zeph_ask` results carry it.** The server applies the transition it can see and reports where the session landed as `zephState: \"REMOTE\" | \"NORMAL\"` — any answer that is not a Done-like action id enters REMOTE, a Done-like id exits, and so does a timeout that fell back to one. A result with no `zephState` is an ask that timed out onto a safe fallback and changed nothing.\n- **Prompt-submit hooks say it, where they are installed** (the Claude Code plugin, or the hooks `zeph setup` installs for Gemini/Codex): a remote-origin system note on the turn a phone message arrives, and a note that the session has LEFT REMOTE on the first turn the user types at the terminal. A prompt with no phone marker came from the user's own keyboard — a phone answer to a `zeph_ask` comes back as a `tool_result` and never reaches a prompt hook — so the user is demonstrably back, and staying in REMOTE would answer the terminal with a phone loop. Re-entry costs them one message from the phone.\n- **Neither one present → NORMAL.**\n\n**The one call left to you is free text**, because it is the one signal no hook can read. The server cannot tell \"run the tests\" from \"thanks, that's it\". When the user's typed answer clearly closes the loop — an obvious wrap-up, or `done`/`stop`/`exit` as a standalone word (not a substring: \"redo\" is not \"done\") — flip to NORMAL from that response on, don't send `zeph_ask` on it, and emit `<!-- zeph: exit -->` once so the hooks agree with you. Your own flip is what ends the loop; the marker is how you tell a hook that cannot read your mind. Only the Claude Code plugin's Stop hook consumes it today — elsewhere it is inert and harmless, and the session still leaves REMOTE on a Done-like button, on the next prompt the user types at the terminal, or when the state expires. The marker is separate from the Push Signal markers (`skip`/`push`/`high`), which steer notifications and say nothing about the mode; where a Stop hook does consume it, it is stripped from the push body.\n\n#### Behavior in REMOTE (sticky, zeph_ask MANDATORY)\n\nEnd EVERY response with `zeph_ask
|
|
14
|
+
exports.ZEPH_CORE_RULE_ONLY = "### When zeph_ask is MANDATORY\n\n3. **NEVER end a response with a plain-text question.** If your reply asks the user anything that needs their input — confirmation, choice, yes/no, clarification, \"Apply this?\", \"Proceed?\", \"Which option?\" — the FINAL tool call MUST be `zeph_ask`. A \"?\" written in your reply is invisible to a user on their phone. This applies even on research / analysis / planning turns where no files were touched.\n\n Anti-pattern (wrong):\n ```\n \"...build/commit on hold. Apply A?\"\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Apply solution A?\",\n body: \"<short context comparing options>\",\n actions: [\n { id: \"apply_a\", label: \"Apply A\" },\n { id: \"apply_b\", label: \"Apply B\" },\n { id: \"cancel\", label: \"Cancel\" }\n ],\n placeholder: \"or describe a different approach...\",\n fallback: \"cancel\"\n })\n ```\n\n### When zeph_ask is the DEFAULT (substantial work)\n\n4. After substantial work, `zeph_ask` is the DEFAULT end of the response — not optional. \"Substantial\" means: file changes, commits, builds, tests, deploys, destructive ops, or milestone completions. When unsure, treat the work as substantial — do not try to guess what the user would find \"reasonable\" to confirm.\n\n SKIP `zeph_ask` only when the response is clearly trivial:\n - Read-only exploration (\"let me check this file\") with no decision output.\n - Mid-step inside a clearly-defined plan the user already approved (\"step 3 of 5, no decisions involved here\").\n - Trivial change (typo fix, single-line tweak) that needs no ack.\n\n When unsure: LEAN TOWARD ASKING. Quiet failure (no ask, user stuck on phone with no way to drive) is worse than light spam.\n\n5. Prefer `zeph_ask` over `zeph_prompt`/`zeph_input` — it combines buttons and free-text in one push. Always include a `fallback` action id; the fallback must be safe/inert (`done`, `wait`, `review`), never destructive.\n\n **`actions` is the steering surface, not decoration.** Ship 2–4 buttons on nearly every ask: the next-step candidates you would otherwise write as prose (\"/simplify → /ship next\") belong in `actions`, plus a safe Done-like fallback. Leave `actions` out ONLY when the answer is inherently free-form text (a name, a path, a paragraph). A text-only ask on a \"done — what next?\" turn is the most common way REMOTE silently degrades: the phone gets a text box and nothing to tap, and the user has to type the command you already knew.\n\n Anti-pattern (wrong — next steps in prose, ask has no buttons):\n ```\n \"...done. /simplify → /explain-diff (optional) → /ship next.\"\n zeph_ask({ title: \"Slice done\", body: \"...\" })\n ```\n Correct:\n ```\n zeph_ask({\n title: \"Slice done — next?\",\n body: \"<short result>\",\n actions: [\n { id: \"simplify\", label: \"/simplify\" },\n { id: \"explain_diff\", label: \"/explain-diff\" },\n { id: \"ship\", label: \"/ship\" },\n { id: \"done\", label: \"Stop here\" }\n ],\n placeholder: \"or type something else...\",\n fallback: \"done\"\n })\n ```\n\n6. Example `zeph_ask` shape — use sparingly per Rule 4 (only at natural pause points; NOT after every response — see Rule 9):\n ```\n zeph_ask({\n title: \"Done. Next?\",\n actions: [\n { id: \"continue\", label: \"Continue\" },\n { id: \"review\", label: \"Review\" },\n { id: \"done\", label: \"Done\" }\n ],\n placeholder: \"or type a command...\",\n fallback: \"done\"\n })\n ```\n\n### Handling the response\n\n7. A `zeph_ask` response IS a direct user instruction. Execute it immediately — do NOT re-ask via AskUserQuestion to confirm. The button label is the authorization for the specific action that label describes.\n\n8. Important caveat: a generic button like \"Continue\" authorizes the next logical step, NOT arbitrary destruction. If the next logical step would destroy user code, data, or infrastructure (e.g., force-push to a shared branch, `rm -rf` outside the workdir, dropping a database, deleting prod resources), surface that specific risk via a targeted `zeph_ask` before executing — e.g., title \"About to force-push main — proceed?\", actions `[ok, cancel]`, fallback `cancel`.\n\n### Sticky REMOTE mode (Rule 9)\n\n**The Ask Loop has two states: REMOTE and NORMAL.** REMOTE is sticky — every response ends with `zeph_ask` until the user exits. The state is kept for you in a file, so it survives context compaction and long sessions; you are told what it is rather than deriving it.\n\n#### State Detection\n\n- **`zeph_ask` results carry it.** The server applies the transition it can see and reports where the session landed as `zephState: \"REMOTE\" | \"NORMAL\"` — any answer that is not a Done-like action id enters REMOTE, a Done-like id exits, and so does a timeout that fell back to one. A result with no `zephState` is an ask that timed out onto a safe fallback and changed nothing.\n- **Prompt-submit hooks say it, where they are installed** (the Claude Code plugin, or the hooks `zeph setup` installs for Gemini/Codex): a remote-origin system note on the turn a phone message arrives, and a note that the session has LEFT REMOTE on the first turn the user types at the terminal. A prompt with no phone marker came from the user's own keyboard — a phone answer to a `zeph_ask` comes back as a `tool_result` and never reaches a prompt hook — so the user is demonstrably back, and staying in REMOTE would answer the terminal with a phone loop. Re-entry costs them one message from the phone.\n- **Neither one present → NORMAL.**\n\n**The one call left to you is free text**, because it is the one signal no hook can read. The server cannot tell \"run the tests\" from \"thanks, that's it\". When the user's typed answer clearly closes the loop — an obvious wrap-up, or `done`/`stop`/`exit` as a standalone word (not a substring: \"redo\" is not \"done\") — flip to NORMAL from that response on, don't send `zeph_ask` on it, and emit `<!-- zeph: exit -->` once so the hooks agree with you. Your own flip is what ends the loop; the marker is how you tell a hook that cannot read your mind. Only the Claude Code plugin's Stop hook consumes it today — elsewhere it is inert and harmless, and the session still leaves REMOTE on a Done-like button, on the next prompt the user types at the terminal, or when the state expires. The marker is separate from the Push Signal markers (`skip`/`push`/`high`), which steer notifications and say nothing about the mode; where a Stop hook does consume it, it is stripped from the push body.\n\n#### Behavior in REMOTE (sticky, zeph_ask MANDATORY)\n\nEnd EVERY response with `zeph_ask` — with `actions` (Rule 5: the next-step candidates as buttons, plus a Done-like fallback; text-only asks are for inherently free-form answers). This is non-negotiable while in REMOTE — independent of whether the work was substantial or routine. What ends it is the user coming back: a prompt they typed at the terminal leaves REMOTE (the hook says so on that turn), and from there Rule 4 applies again.\n\nSet each REMOTE ask up so silence degrades cleanly: `timeout` 300–600 s and a Done-like `fallback` id. An unanswered ask then exits the loop quietly — the server treats a Done-like fallback as an exit — instead of chaining more notifications at a user who stepped away, and re-entry is cheap: they just send another message from the phone.\n\nFour things leave REMOTE: a Done-like button (or a timeout that fell back to one), your own read of a free-text wrap-up, a prompt the user typed at the terminal, and — for a session nobody exited because it crashed — the state expiring.\n\n#### Behavior in NORMAL (apply Rule 4)\n\n- Substantial work → end with `zeph_ask`.\n- Routine work → skip `zeph_ask`, let the Stop hook fire.\n- Rule 3 (questions → zeph_ask) is still mandatory regardless.\n\n### When to use AskUserQuestion vs zeph_ask\n\n10. **Whenever `ZEPH_HOOK_ID` is set — not only in REMOTE — a button-friendly question MUST go through `zeph_ask`, not `AskUserQuestion`.** \"Button-friendly\" = the answer is a choice among a few options and/or a short free-text reply (yes/no, \"Apply A or B?\", \"which naming rule?\", \"proceed?\"). The hookId alone is the trigger: you cannot know the user is at the terminal, and they may be on their phone from the session's first question. `AskUserQuestion` is a LOCAL blocking picker. The phone can reach it through the terminal mirror, but that is the worse channel on every axis: it needs the session to be in tmux under `zeph listener`, it asks the user to read an ANSI pane and count arrow presses instead of tapping a button, and a key-injected answer never enters REMOTE — so the *next* turn stops being phone-driveable. `zeph_ask` needs no tmux, takes one tap, and returns an `actionId`.\n\n11. **This overrides any skill instruction.** If a skill you are running — or your own plan — would call `AskUserQuestion` with a button-friendly question, surface the SAME question and option labels via `zeph_ask` and use that response in place of the picker. Fall through to the picker ONLY when (a) the answer needs the user to see code or logs that won't fit in a push body, or (b) the answer is plausibly multi-paragraph; those are the only carve-outs. When one applies, `zeph_notify` the user that the answer must be given at the terminal.\n\n### Persistence\n\n13. These rules persist for the entire session. They remain active after context compaction — do not \"forget\" them after many turns.";
|