@tryglen/cli 0.22.0 → 0.24.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +3 -3
  2. package/dist/_utils/agent-adapter.d.ts +3 -0
  3. package/dist/_utils/agent-adapter.js +4 -1
  4. package/dist/_utils/agent-adapter.js.map +1 -1
  5. package/dist/_utils/agents-table.d.ts +4 -3
  6. package/dist/_utils/agents-table.js +18 -1
  7. package/dist/_utils/agents-table.js.map +1 -1
  8. package/dist/_utils/config.js +1 -5
  9. package/dist/_utils/config.js.map +1 -1
  10. package/dist/_utils/detect-transcript-format.d.ts +1 -1
  11. package/dist/_utils/detect-transcript-format.js +13 -2
  12. package/dist/_utils/detect-transcript-format.js.map +1 -1
  13. package/dist/_utils/format-search-result.js +15 -49
  14. package/dist/_utils/format-search-result.js.map +1 -1
  15. package/dist/_utils/http.js +12 -1
  16. package/dist/_utils/http.js.map +1 -1
  17. package/dist/_utils/parse-pi-transcript.d.ts +3 -0
  18. package/dist/_utils/parse-pi-transcript.js +113 -0
  19. package/dist/_utils/parse-pi-transcript.js.map +1 -0
  20. package/dist/_utils/plugin-status.d.ts +1 -1
  21. package/dist/_utils/plugin-status.js +46 -2
  22. package/dist/_utils/plugin-status.js.map +1 -1
  23. package/dist/_utils/transcript-turns.d.ts +1 -1
  24. package/dist/bin.js +14 -8
  25. package/dist/bin.js.map +1 -1
  26. package/dist/commands/artifact.d.ts +1 -0
  27. package/dist/commands/artifact.js +9 -2
  28. package/dist/commands/artifact.js.map +1 -1
  29. package/dist/commands/doctor.js +29 -0
  30. package/dist/commands/doctor.js.map +1 -1
  31. package/dist/commands/import.js +13 -9
  32. package/dist/commands/import.js.map +1 -1
  33. package/dist/commands/ingest.js +60 -24
  34. package/dist/commands/ingest.js.map +1 -1
  35. package/dist/commands/install.d.ts +1 -0
  36. package/dist/commands/install.js +12 -6
  37. package/dist/commands/install.js.map +1 -1
  38. package/dist/commands/session-start.js +1 -1
  39. package/dist/commands/uninstall.js +6 -1
  40. package/dist/commands/uninstall.js.map +1 -1
  41. package/package.json +1 -1
package/README.md CHANGED
@@ -17,12 +17,12 @@ glen login
17
17
  | `glen logout` | Sign out and remove credentials + session state. |
18
18
  | `glen status` | Show connection status, active org, incognito state, and CLI version. |
19
19
  | `glen search "<query>"` | Search the team's shared glen memory. |
20
- | `glen import <path…> [--dry-run]` | Import old local agent transcripts (Claude Code `~/.claude/projects`, Codex `~/.codex/sessions`, Cursor `state.vscdb`) into glen memory. Idempotent — re-running skips already-imported turns. `--dry-run` previews without writing. |
20
+ | `glen import <path…> [--dry-run]` | Import old local agent transcripts (Claude Code `~/.claude/projects`, Codex `~/.codex/sessions`, Cursor `state.vscdb`, Pi `~/.pi/agent/sessions`) into glen memory. Idempotent — re-running skips already-imported turns. `--dry-run` previews without writing. |
21
21
  | `glen incognito on\|off` | Toggle incognito mode: while on, nothing is recorded (recall keeps working). |
22
22
  | `glen org list` | List your organizations; active one is marked with `✓`. |
23
23
  | `glen org switch [slug]` | Switch the active organization for this machine (interactive picker without `slug`). |
24
- | `glen ingest [--agent <name>]` | Ingest a turn from stdin — used by agent hooks (`claude-code` or `codex`). |
25
- | `glen install [--agent <claude\|codex>]` | Set up or update glen for detected coding agents (plugin + hooks); idempotent, so re-running repairs a broken setup. `--claude-path <path>` / `--codex-path <path>` point at a binary when auto-detection fails. |
24
+ | `glen ingest [--agent <name>]` | Ingest a turn from stdin — used by agent hooks (`claude-code`, `codex`, `cursor`, or `pi`). |
25
+ | `glen install [--agent <claude\|codex\|cursor\|pi>]` | Set up or update glen for detected coding agents (plugin + hooks); idempotent, so re-running repairs a broken setup. `--claude-path <path>` / `--codex-path <path>` / `--pi-path <path>` point at a binary when auto-detection fails. |
26
26
  | `glen update` | Update the glen CLI **and** any installed glen plugins, and re-verify the Codex hook registration. Never installs a plugin that isn't already installed — that's `glen install`'s job. |
27
27
  | `glen doctor [--auto]` | Print machine-readable `status:` lines (CLI version/latest/channel, login + org, per-agent plugin + hook state) plus `→` remedy lines — the setup skill branches on them. `--auto` runs background updates silently (used by hooks). |
28
28
  | `glen statusline` | Output a single status line for the agent's UI status bar — used by hooks. |
@@ -11,6 +11,9 @@ type AdapterOutput = {
11
11
  *
12
12
  * - "codex": reads model/permission_mode/source + last_assistant_message
13
13
  * directly from the event (no transcript file).
14
+ * - "pi": same event-carried shape as codex — the events are authored by
15
+ * glen's own pi extension (packages/pi-plugin/extensions/glen.ts); pi's
16
+ * session file is a pi-specific JSONL tree glen doesn't parse.
14
17
  * - "claude-code" and generic/unknown: uses parseTranscript for priorAssistant
15
18
  * and the user-message index (nextUserMessageIndex) that callers need for
16
19
  * idempotency key derivation.
@@ -7,6 +7,9 @@ const str = (v) => typeof v === "string" && v ? v : null;
7
7
  *
8
8
  * - "codex": reads model/permission_mode/source + last_assistant_message
9
9
  * directly from the event (no transcript file).
10
+ * - "pi": same event-carried shape as codex — the events are authored by
11
+ * glen's own pi extension (packages/pi-plugin/extensions/glen.ts); pi's
12
+ * session file is a pi-specific JSONL tree glen doesn't parse.
10
13
  * - "claude-code" and generic/unknown: uses parseTranscript for priorAssistant
11
14
  * and the user-message index (nextUserMessageIndex) that callers need for
12
15
  * idempotency key derivation.
@@ -26,7 +29,7 @@ const adaptAgentEvent = (agent, event, transcriptLines) => {
26
29
  usesTranscript: false,
27
30
  };
28
31
  }
29
- if (agent === "codex") {
32
+ if (agent === "codex" || agent === "pi") {
30
33
  const fields = {};
31
34
  const model = str(event.model);
32
35
  if (model)
@@ -1 +1 @@
1
- {"version":3,"file":"agent-adapter.js","sourceRoot":"","sources":["../../src/_utils/agent-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAaxD,gDAAgD;AAChD,MAAM,GAAG,GAAG,CAAC,CAAU,EAAiB,EAAE,CACxC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAExC;;;;;;;;;GASG;AACH,MAAM,eAAe,GAAG,CACtB,KAAyB,EACzB,KAAgB,EAChB,eAAkC,EACnB,EAAE;IACjB,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,yEAAyE;QACzE,oEAAoE;QACpE,8DAA8D;QAC9D,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,KAAK;YAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAChC,OAAO;YACL,aAAa,EAAE,MAAM;YACrB,cAAc,EAAE,IAAI;YACpB,cAAc,EAAE,KAAK;SACtB,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,KAAK;YAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAChC,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAClD,IAAI,cAAc;YAAE,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;QAC3D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,MAAM;YAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACnC,OAAO;YACL,aAAa,EAAE,MAAM;YACrB,cAAc,EACZ,OAAO,KAAK,CAAC,sBAAsB,KAAK,QAAQ;gBAC9C,CAAC,CAAC,KAAK,CAAC,sBAAsB;gBAC9B,CAAC,CAAC,IAAI;YACV,cAAc,EAAE,KAAK;SACtB,CAAC;IACJ,CAAC;IAED,iFAAiF;IACjF,MAAM,EAAE,cAAc,EAAE,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAClD,IAAI,cAAc;QAAE,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;IAC3D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,MAAM;QAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACnC,OAAO;QACL,aAAa,EAAE,MAAM;QACrB,cAAc;QACd,cAAc,EAAE,IAAI;KACrB,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"agent-adapter.js","sourceRoot":"","sources":["../../src/_utils/agent-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAaxD,gDAAgD;AAChD,MAAM,GAAG,GAAG,CAAC,CAAU,EAAiB,EAAE,CACxC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,MAAM,eAAe,GAAG,CACtB,KAAyB,EACzB,KAAgB,EAChB,eAAkC,EACnB,EAAE;IACjB,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,yEAAyE;QACzE,oEAAoE;QACpE,8DAA8D;QAC9D,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,KAAK;YAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAChC,OAAO;YACL,aAAa,EAAE,MAAM;YACrB,cAAc,EAAE,IAAI;YACpB,cAAc,EAAE,KAAK;SACtB,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACxC,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,KAAK;YAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAChC,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAClD,IAAI,cAAc;YAAE,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;QAC3D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,MAAM;YAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACnC,OAAO;YACL,aAAa,EAAE,MAAM;YACrB,cAAc,EACZ,OAAO,KAAK,CAAC,sBAAsB,KAAK,QAAQ;gBAC9C,CAAC,CAAC,KAAK,CAAC,sBAAsB;gBAC9B,CAAC,CAAC,IAAI;YACV,cAAc,EAAE,KAAK;SACtB,CAAC;IACJ,CAAC;IAED,iFAAiF;IACjF,MAAM,EAAE,cAAc,EAAE,GAAG,eAAe,CAAC,eAAe,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAClD,IAAI,cAAc;QAAE,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;IAC3D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,MAAM;QAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACnC,OAAO;QACL,aAAa,EAAE,MAAM;QACrB,cAAc;QACd,cAAc,EAAE,IAAI;KACrB,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -1,10 +1,11 @@
1
+ declare const PI_PLUGIN_SOURCE = "git:github.com/Glen-Web-App/glen-pi-plugin";
1
2
  type Agent = {
2
3
  readonly name: string;
3
- readonly bin: "claude" | "codex";
4
+ readonly bin: "claude" | "codex" | "pi";
4
5
  readonly steps: readonly (readonly string[])[];
5
6
  readonly updateSteps: readonly (readonly string[])[];
6
- readonly postInstall: "claude" | "codex";
7
+ readonly postInstall: "claude" | "codex" | "pi";
7
8
  };
8
9
  declare const AGENTS: readonly Agent[];
9
- export { AGENTS };
10
+ export { AGENTS, PI_PLUGIN_SOURCE };
10
11
  export type { Agent };
@@ -1,3 +1,13 @@
1
+ // ---------------------------------------------------------------------------
2
+ // AGENTS table — steps arrays drive the install sequence; updateSteps run
3
+ // instead when the glen plugin is already installed (converge semantics).
4
+ // Steps are run sequentially; a failed step (e.g. `marketplace add` already
5
+ // exists) must NOT block the following steps.
6
+ // ---------------------------------------------------------------------------
7
+ // Pi has no marketplace — its package manager installs straight from the dist
8
+ // repo. One source string, shared by install/update/doctor/uninstall so the
9
+ // registration and its converge/removal steps can never drift.
10
+ const PI_PLUGIN_SOURCE = "git:github.com/Glen-Web-App/glen-pi-plugin";
1
11
  const AGENTS = [
2
12
  {
3
13
  name: "Claude Code",
@@ -21,6 +31,13 @@ const AGENTS = [
21
31
  updateSteps: [["plugin", "marketplace", "upgrade", "glen"]],
22
32
  postInstall: "codex",
23
33
  },
34
+ {
35
+ name: "Pi",
36
+ bin: "pi",
37
+ steps: [["install", PI_PLUGIN_SOURCE]],
38
+ updateSteps: [["update", PI_PLUGIN_SOURCE]],
39
+ postInstall: "pi",
40
+ },
24
41
  ];
25
- export { AGENTS };
42
+ export { AGENTS, PI_PLUGIN_SOURCE };
26
43
  //# sourceMappingURL=agents-table.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agents-table.js","sourceRoot":"","sources":["../../src/_utils/agents-table.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,GAAqB;IAC/B;QACE,IAAI,EAAE,aAAa;QACnB,GAAG,EAAE,QAAQ;QACb,KAAK,EAAE;YACL,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,sCAAsC,CAAC;YACxE,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC;SACnC;QACD,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAChD,WAAW,EAAE,QAAQ;KACtB;IACD;QACE,IAAI,EAAE,OAAO;QACb,GAAG,EAAE,OAAO;QACZ,KAAK,EAAE;YACL,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,gCAAgC,CAAC;YAClE,qEAAqE;YACrE,4DAA4D;YAC5D,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC;SAC/B;QACD,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC3D,WAAW,EAAE,OAAO;KACrB;CACF,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
1
+ {"version":3,"file":"agents-table.js","sourceRoot":"","sources":["../../src/_utils/agents-table.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAC1E,0EAA0E;AAC1E,4EAA4E;AAC5E,8CAA8C;AAC9C,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,+DAA+D;AAC/D,MAAM,gBAAgB,GAAG,4CAA4C,CAAC;AAUtE,MAAM,MAAM,GAAqB;IAC/B;QACE,IAAI,EAAE,aAAa;QACnB,GAAG,EAAE,QAAQ;QACb,KAAK,EAAE;YACL,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,sCAAsC,CAAC;YACxE,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC;SACnC;QACD,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAChD,WAAW,EAAE,QAAQ;KACtB;IACD;QACE,IAAI,EAAE,OAAO;QACb,GAAG,EAAE,OAAO;QACZ,KAAK,EAAE;YACL,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,gCAAgC,CAAC;YAClE,qEAAqE;YACrE,4DAA4D;YAC5D,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC;SAC/B;QACD,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC3D,WAAW,EAAE,OAAO;KACrB;IACD;QACE,IAAI,EAAE,IAAI;QACV,GAAG,EAAE,IAAI;QACT,KAAK,EAAE,CAAC,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;QACtC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QAC3C,WAAW,EAAE,IAAI;KAClB;CACF,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC"}
@@ -23,11 +23,7 @@ const config = {
23
23
  setRecordingUrl: `${baseUrl}/api/mcp/route/setRecording`,
24
24
  setSuggestionsUrl: `${baseUrl}/api/mcp/route/setSuggestions`,
25
25
  ingestTimeoutMs: 8000,
26
- // 30s: a broad "summarize everything" search runs two sequential LLM relevance
27
- // scans (coarse shards → fine observations) and legitimately lands ~15s on heavy
28
- // queries; a flat 15s clipped answers the server had already computed. Also the
29
- // shared timeout for every /api/mcp/route/* POST via post-route.ts.
30
- searchTimeoutMs: 30_000,
26
+ searchTimeoutMs: 60_000,
31
27
  forgetTimeoutMs: 15_000,
32
28
  listOrgsTimeoutMs: 15_000,
33
29
  commitAnchorTimeoutMs: 3000,
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/_utils/config.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gEAAgE;AAChE,MAAM,OAAO,GAAG,CACd,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,yBAAyB,CACvD,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEtB,MAAM,MAAM,GAAG;IACb,OAAO;IACP,UAAU,EAAE,GAAG,OAAO,cAAc;IACpC,WAAW,EAAE,GAAG,OAAO,2BAA2B;IAClD,OAAO,EAAE,GAAG,OAAO,qBAAqB;IACxC,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,SAAS,EAAE,GAAG,OAAO,6BAA6B;IAClD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,mBAAmB,EAAE,GAAG,OAAO,iCAAiC;IAChE,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,eAAe,EAAE,GAAG,OAAO,6BAA6B;IACxD,aAAa,EAAE,GAAG,OAAO,2BAA2B;IACpD,SAAS,EAAE,GAAG,OAAO,iCAAiC;IACtD,eAAe,EAAE,GAAG,OAAO,6BAA6B;IACxD,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,eAAe,EAAE,IAAI;IACrB,+EAA+E;IAC/E,iFAAiF;IACjF,gFAAgF;IAChF,oEAAoE;IACpE,eAAe,EAAE,MAAM;IACvB,eAAe,EAAE,MAAM;IACvB,iBAAiB,EAAE,MAAM;IACzB,qBAAqB,EAAE,IAAI;IAC3B,oFAAoF;IACpF,mBAAmB,EAAE,MAAM;IAC3B,8EAA8E;IAC9E,eAAe,EAAE,MAAM;IACvB,qBAAqB,EAAE,MAAM;IAC7B,uBAAuB,EAAE,MAAM;CAChC,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/_utils/config.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gEAAgE;AAChE,MAAM,OAAO,GAAG,CACd,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,yBAAyB,CACvD,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEtB,MAAM,MAAM,GAAG;IACb,OAAO;IACP,UAAU,EAAE,GAAG,OAAO,cAAc;IACpC,WAAW,EAAE,GAAG,OAAO,2BAA2B;IAClD,OAAO,EAAE,GAAG,OAAO,qBAAqB;IACxC,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,SAAS,EAAE,GAAG,OAAO,uBAAuB;IAC5C,SAAS,EAAE,GAAG,OAAO,6BAA6B;IAClD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,WAAW,EAAE,GAAG,OAAO,yBAAyB;IAChD,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,mBAAmB,EAAE,GAAG,OAAO,iCAAiC;IAChE,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,cAAc,EAAE,GAAG,OAAO,4BAA4B;IACtD,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,eAAe,EAAE,GAAG,OAAO,6BAA6B;IACxD,aAAa,EAAE,GAAG,OAAO,2BAA2B;IACpD,SAAS,EAAE,GAAG,OAAO,iCAAiC;IACtD,eAAe,EAAE,GAAG,OAAO,6BAA6B;IACxD,iBAAiB,EAAE,GAAG,OAAO,+BAA+B;IAC5D,eAAe,EAAE,IAAI;IACrB,eAAe,EAAE,MAAM;IACvB,eAAe,EAAE,MAAM;IACvB,iBAAiB,EAAE,MAAM;IACzB,qBAAqB,EAAE,IAAI;IAC3B,oFAAoF;IACpF,mBAAmB,EAAE,MAAM;IAC3B,8EAA8E;IAC9E,eAAe,EAAE,MAAM;IACvB,qBAAqB,EAAE,MAAM;IAC7B,uBAAuB,EAAE,MAAM;CAChC,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -1,2 +1,2 @@
1
- declare const detectTranscriptFormat: (filePath: string, sampleLines: readonly string[]) => "claude-code" | "codex" | "cursor" | null;
1
+ declare const detectTranscriptFormat: (filePath: string, sampleLines: readonly string[]) => "claude-code" | "codex" | "cursor" | "pi" | null;
2
2
  export { detectTranscriptFormat };
@@ -17,10 +17,12 @@ const CODEX_ENVELOPE_TYPES = new Set([
17
17
  "compacted",
18
18
  ]);
19
19
  // Sniff which agent wrote a transcript file. Cursor is identified by its
20
- // SQLite container; the two JSONL formats are told apart by their envelopes:
20
+ // SQLite container; the JSONL formats are told apart by their envelopes:
21
21
  // Claude Code lines carry uuid/parentUuid tree fields, Codex rollout lines a
22
22
  // {timestamp, type, payload} wrapper (or, pre-envelope, bare Responses-API
23
- // message items with input_text/output_text parts).
23
+ // message items with input_text/output_text parts), and pi session files a
24
+ // {type:"session", version, cwd} header plus id/parentId entries wrapping a
25
+ // nested message object.
24
26
  const detectTranscriptFormat = (filePath, sampleLines) => {
25
27
  if (filePath.endsWith(".vscdb"))
26
28
  return "cursor";
@@ -34,6 +36,15 @@ const detectTranscriptFormat = (filePath, sampleLines) => {
34
36
  if (typeof e.sessionId === "string" &&
35
37
  (e.type === "user" || e.type === "assistant" || e.type === "summary"))
36
38
  return "claude-code";
39
+ if (e.type === "session" &&
40
+ typeof e.version === "number" &&
41
+ typeof e.cwd === "string")
42
+ return "pi";
43
+ if (e.type === "message" &&
44
+ "parentId" in e &&
45
+ e.message !== null &&
46
+ typeof e.message === "object")
47
+ return "pi";
37
48
  if (typeof e.type === "string" &&
38
49
  CODEX_ENVELOPE_TYPES.has(e.type) &&
39
50
  "payload" in e)
@@ -1 +1 @@
1
- {"version":3,"file":"detect-transcript-format.js","sourceRoot":"","sources":["../../src/_utils/detect-transcript-format.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,CAAC,IAAY,EAAgB,EAAE;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;QAC3C,OAAO,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;YAClD,CAAC,CAAE,MAAgB;YACnB,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,cAAc;IACd,eAAe;IACf,WAAW;IACX,cAAc;IACd,WAAW;CACZ,CAAC,CAAC;AAEH,yEAAyE;AACzE,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAC3E,oDAAoD;AACpD,MAAM,sBAAsB,GAAG,CAC7B,QAAgB,EAChB,WAA8B,EACa,EAAE;IAC7C,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IACjD,OAAO,CACL,WAAW;SACR,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;SACZ,GAAG,CAAC,SAAS,CAAC;SACd,MAAM,CAAC,CAAC,CAAC,EAAc,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;SACrC,GAAG,CAAC,CAAC,CAAC,EAAkC,EAAE;QACzC,IAAI,YAAY,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC;YAAE,OAAO,aAAa,CAAC;QAC/D,IACE,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;YAC/B,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;YAErE,OAAO,aAAa,CAAC;QACvB,IACE,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ;YAC1B,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAChC,SAAS,IAAI,CAAC;YAEd,OAAO,OAAO,CAAC;QACjB,IACE,CAAC,CAAC,IAAI,KAAK,SAAS;YACpB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;YACxB,CAAC,CAAC,OAAO,CAAC,IAAI,CACZ,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,KAAK,IAAI;gBACV,OAAO,CAAC,KAAK,QAAQ;gBACrB,CAAE,CAAW,CAAC,IAAI,KAAK,YAAY;oBAChC,CAAW,CAAC,IAAI,KAAK,aAAa,CAAC,CACzC;YAED,OAAO,OAAO,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,CACnC,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"detect-transcript-format.js","sourceRoot":"","sources":["../../src/_utils/detect-transcript-format.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,CAAC,IAAY,EAAgB,EAAE;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;QAC3C,OAAO,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;YAClD,CAAC,CAAE,MAAgB;YACnB,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,cAAc;IACd,eAAe;IACf,WAAW;IACX,cAAc;IACd,WAAW;CACZ,CAAC,CAAC;AAEH,yEAAyE;AACzE,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,2EAA2E;AAC3E,4EAA4E;AAC5E,yBAAyB;AACzB,MAAM,sBAAsB,GAAG,CAC7B,QAAgB,EAChB,WAA8B,EACoB,EAAE;IACpD,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IACjD,OAAO,CACL,WAAW;SACR,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;SACZ,GAAG,CAAC,SAAS,CAAC;SACd,MAAM,CAAC,CAAC,CAAC,EAAc,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;SACrC,GAAG,CAAC,CAAC,CAAC,EAAyC,EAAE;QAChD,IAAI,YAAY,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC;YAAE,OAAO,aAAa,CAAC;QAC/D,IACE,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;YAC/B,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;YAErE,OAAO,aAAa,CAAC;QACvB,IACE,CAAC,CAAC,IAAI,KAAK,SAAS;YACpB,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ;YAC7B,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ;YAEzB,OAAO,IAAI,CAAC;QACd,IACE,CAAC,CAAC,IAAI,KAAK,SAAS;YACpB,UAAU,IAAI,CAAC;YACf,CAAC,CAAC,OAAO,KAAK,IAAI;YAClB,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ;YAE7B,OAAO,IAAI,CAAC;QACd,IACE,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ;YAC1B,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAChC,SAAS,IAAI,CAAC;YAEd,OAAO,OAAO,CAAC;QACjB,IACE,CAAC,CAAC,IAAI,KAAK,SAAS;YACpB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;YACxB,CAAC,CAAC,OAAO,CAAC,IAAI,CACZ,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,KAAK,IAAI;gBACV,OAAO,CAAC,KAAK,QAAQ;gBACrB,CAAE,CAAW,CAAC,IAAI,KAAK,YAAY;oBAChC,CAAW,CAAC,IAAI,KAAK,aAAa,CAAC,CACzC;YAED,OAAO,OAAO,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,CACnC,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
@@ -1,59 +1,25 @@
1
- // `glen search` returns a `context` block: one recalled memory per line, each
2
- // formatted "[timestamp] Author: content", with an optional "…[N omitted]…"
3
- // elision marker where the middle was truncated. The agent reads this output
4
- // directly, so we lead with a short receipt of how many memories came back and
5
- // render each as a bullet — a few bullets on what was returned, rather than an
6
- // undifferentiated block — and close with a one-line reliability caveat.
7
- // Returns null when there's no context to show.
8
- const ELISION = /^…\[\d+ omitted\]…$/;
9
- // Memories are LLM-extracted from past sessions — they can be stale, partial, or
10
- // contradict each other. The nudge tells the agent to run `glen search` via Bash,
11
- // which does NOT load skills/search/SKILL.md, so the caveat has to travel with the
12
- // result itself rather than living only in the skill (same for the stale→forget
13
- // instruction, whose full guardrails live in skills/forget/SKILL.md). Kept short —
14
- // it rides every non-empty result.
1
+ // `answer` is already fully rendered server-side (render-answer.ts appends the
2
+ // "Sources:"/"Couldn't verify:" sections), so print it as-is — re-deriving
3
+ // bullets/gaps here would double-render those sections.
15
4
  const CAVEAT = "(Recalled from past sessions — may be outdated or conflicting. Weigh recency, " +
16
5
  "use your judgment on what's relevant, and confirm with the user before relying " +
17
- "on anything uncertain or contradictory. If you VERIFY a memory is stale — the " +
18
- "current code or state you've checked directly contradicts it — run " +
19
- "`glen forget <id>` via Bash with its [m:<id>] handle, tell the user what you " +
20
- "forgot and why (it's restorable from the dashboard), and state the correct " +
21
- "fact so glen re-learns it. Never forget on suspicion alone or because two " +
22
- "memories disagree — surface those to the user instead.)";
23
- // When a search returns memories the agent judges genuinely useful for the
24
- // current request, we want the *user* — not just the agent — to see that Glen
25
- // helped. The agent reads this result from a Bash call (the search skill isn't
26
- // loaded), so the instruction has to ride the result itself, like the caveat.
27
- // We hand the agent a single-cell Markdown table as a fixed scaffold and let it
28
- // author only the inner 1–3 sentence summary: copying the fragile `| … |` / `| --- |`
29
- // lines verbatim keeps the box from collapsing, while the summary stays
30
- // context-aware. It's gated twice — the CLI appends this only when memories came
31
- // back, and the agent renders it only when one actually matters here — so the box
32
- // means "Glen surfaced something useful", not merely "Glen ran". The one-line / no-`|`
33
- // rule is what stops the single cell from breaking apart.
34
- const BANNER = "If one or more of the recalled memories above is genuinely useful for the " +
35
- "user's current request, BEGIN your reply with the two-line banner below — copy " +
36
- "both lines exactly, replacing only the angle-bracketed text with a 1–3 sentence " +
37
- "summary of that useful context and why it matters here. Keep it on ONE line: " +
38
- 'never put a "|" character or a line break inside it. If nothing above is ' +
39
- "actually relevant, skip the banner entirely and don't mention Glen.\n" +
6
+ "on anything uncertain or contradictory.)";
7
+ // Rides the result (Bash `glen search` loads no skill). The agent fills only the
8
+ // inner cell text; the one-line/no-`|` rule keeps the single-cell table from collapsing.
9
+ const BANNER = "If the answer above is genuinely useful for the user's current request, " +
10
+ "BEGIN your reply with the two-line banner below — copy both lines exactly, " +
11
+ "replacing only the angle-bracketed text with a 1–3 sentence summary of that " +
12
+ "useful context and why it matters here. Keep it on ONE line: never put a " +
13
+ '"|" character or a line break inside it. If nothing above is actually ' +
14
+ "relevant, skip the banner entirely and don't mention Glen.\n" +
40
15
  "\n" +
41
16
  "| 🧠 **Glen** — <1–3 sentences: the useful context and why it matters here> |\n" +
42
17
  "| --- |";
43
18
  const formatSearchResult = (result) => {
44
- const context = result?.context;
45
- if (typeof context !== "string" || context.trim() === "")
19
+ const answer = result?.answer;
20
+ if (typeof answer !== "string" || answer.trim() === "")
46
21
  return null;
47
- const lines = context.split("\n").filter((l) => l.trim() !== "");
48
- const memoryCount = lines.filter((l) => !ELISION.test(l.trim())).length;
49
- if (memoryCount === 0)
50
- return null;
51
- const noun = memoryCount === 1 ? "memory" : "memories";
52
- const bullets = lines
53
- // The elision marker isn't a memory — keep it inline (indented), un-bulleted.
54
- .map((l) => (ELISION.test(l.trim()) ? ` ${l.trim()}` : `• ${l}`))
55
- .join("\n");
56
- return `[glen] recalled ${memoryCount} ${noun}:\n${bullets}\n${CAVEAT}\n\n${BANNER}`;
22
+ return `[glen] search answer:\n\n${answer}\n\n${CAVEAT}\n\n${BANNER}`;
57
23
  };
58
24
  export { formatSearchResult };
59
25
  //# sourceMappingURL=format-search-result.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"format-search-result.js","sourceRoot":"","sources":["../../src/_utils/format-search-result.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,yEAAyE;AACzE,gDAAgD;AAChD,MAAM,OAAO,GAAG,qBAAqB,CAAC;AAEtC,iFAAiF;AACjF,kFAAkF;AAClF,mFAAmF;AACnF,gFAAgF;AAChF,mFAAmF;AACnF,mCAAmC;AACnC,MAAM,MAAM,GACV,gFAAgF;IAChF,iFAAiF;IACjF,gFAAgF;IAChF,qEAAqE;IACrE,+EAA+E;IAC/E,6EAA6E;IAC7E,4EAA4E;IAC5E,yDAAyD,CAAC;AAE5D,2EAA2E;AAC3E,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAC9E,gFAAgF;AAChF,sFAAsF;AACtF,wEAAwE;AACxE,iFAAiF;AACjF,kFAAkF;AAClF,uFAAuF;AACvF,0DAA0D;AAC1D,MAAM,MAAM,GACV,4EAA4E;IAC5E,iFAAiF;IACjF,kFAAkF;IAClF,+EAA+E;IAC/E,2EAA2E;IAC3E,uEAAuE;IACvE,IAAI;IACJ,iFAAiF;IACjF,SAAS,CAAC;AAEZ,MAAM,kBAAkB,GAAG,CAAC,MAAe,EAAiB,EAAE;IAC5D,MAAM,OAAO,GAAI,MAAyC,EAAE,OAAO,CAAC;IACpE,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAEtE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACxE,IAAI,WAAW,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,IAAI,GAAG,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;IACvD,MAAM,OAAO,GAAG,KAAK;QACnB,8EAA8E;SAC7E,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;SACjE,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,mBAAmB,WAAW,IAAI,IAAI,MAAM,OAAO,KAAK,MAAM,OAAO,MAAM,EAAE,CAAC;AACvF,CAAC,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"format-search-result.js","sourceRoot":"","sources":["../../src/_utils/format-search-result.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,2EAA2E;AAC3E,wDAAwD;AACxD,MAAM,MAAM,GACV,gFAAgF;IAChF,iFAAiF;IACjF,0CAA0C,CAAC;AAE7C,iFAAiF;AACjF,yFAAyF;AACzF,MAAM,MAAM,GACV,0EAA0E;IAC1E,6EAA6E;IAC7E,8EAA8E;IAC9E,2EAA2E;IAC3E,wEAAwE;IACxE,8DAA8D;IAC9D,IAAI;IACJ,iFAAiF;IACjF,SAAS,CAAC;AAEZ,MAAM,kBAAkB,GAAG,CAAC,MAAe,EAAiB,EAAE;IAC5D,MAAM,MAAM,GAAI,MAAyC,EAAE,MAAM,CAAC;IAClE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAEpE,OAAO,4BAA4B,MAAM,OAAO,MAAM,OAAO,MAAM,EAAE,CAAC;AACxE,CAAC,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -40,13 +40,24 @@ const classifyFetchError = (e, url) => {
40
40
  };
41
41
  const httpJson = async (url, options = {}) => {
42
42
  const { method = "GET", headers, body, timeoutMs } = options;
43
+ // Staging/preview deployments sit behind Vercel deployment protection; the
44
+ // bypass token must ride on EVERY request or Vercel 401s before the app
45
+ // runs. Env-gated so production use (unset) sends nothing extra — pairs
46
+ // with GLEN_BASE_URL for pointing the CLI at a preview deploy.
47
+ const bypassToken = process.env.GLEN_VERCEL_PROTECTION_BYPASS;
48
+ const mergedHeaders = {
49
+ ...(bypassToken ? { "x-vercel-protection-bypass": bypassToken } : {}),
50
+ ...headers,
51
+ };
43
52
  const controller = new AbortController();
44
53
  const timeoutId = timeoutMs
45
54
  ? setTimeout(() => controller.abort(), timeoutMs)
46
55
  : undefined;
47
56
  const fetchResult = await fromPromise(fetch(url, {
48
57
  method,
49
- ...(headers !== undefined ? { headers } : {}),
58
+ ...(Object.keys(mergedHeaders).length > 0
59
+ ? { headers: mergedHeaders }
60
+ : {}),
50
61
  body: body ?? null,
51
62
  signal: controller.signal,
52
63
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/_utils/http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/_utils/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ParsedTranscript } from "./transcript-turns.js";
2
+ declare const parsePiTranscript: (lines: readonly string[], fallbackSessionId: string) => ParsedTranscript | null;
3
+ export { parsePiTranscript };
@@ -0,0 +1,113 @@
1
+ const parseLine = (line) => {
2
+ try {
3
+ const parsed = JSON.parse(line);
4
+ return parsed !== null && typeof parsed === "object"
5
+ ? parsed
6
+ : null;
7
+ }
8
+ catch {
9
+ return null;
10
+ }
11
+ };
12
+ const messageOf = (e) => e.message !== null && typeof e.message === "object"
13
+ ? e.message
14
+ : null;
15
+ // Text of a pi message: a plain string (typical human prompt) or the
16
+ // concatenated `text` content blocks (assistant output; thinking/toolCall/
17
+ // image blocks are not conversation text).
18
+ const textOf = (content) => {
19
+ if (typeof content === "string")
20
+ return content;
21
+ if (!Array.isArray(content))
22
+ return "";
23
+ return content
24
+ .filter((p) => p !== null &&
25
+ typeof p === "object" &&
26
+ p.type === "text" &&
27
+ typeof p.text === "string")
28
+ .map((p) => p.text)
29
+ .join("\n");
30
+ };
31
+ // Pi entries form a tree via id → parentId (branching via /fork and tree
32
+ // navigation creates alternates). Follow the chain up from the active leaf —
33
+ // the last CONVERSATION entry (a message whose role is user/assistant) that is
34
+ // nobody's parent — so abandoned branches aren't imported twice. Restricting
35
+ // leaf candidates to conversation entries matters: bookkeeping entries
36
+ // (labels, custom extension state, model changes) can trail the file as
37
+ // childless nodes, and picking one of those would walk a one-entry branch.
38
+ // Falls back to file order when the chain is unwalkable (format drift).
39
+ const activeBranch = (entries) => {
40
+ const withId = entries.filter((e) => typeof e.id === "string");
41
+ const byId = new Map(withId.map((e) => [e.id, e]));
42
+ const parents = new Set(entries
43
+ .map((e) => e.parentId)
44
+ .filter((p) => typeof p === "string"));
45
+ const childless = [...withId]
46
+ .reverse()
47
+ .filter((e) => !parents.has(e.id));
48
+ const leaf = childless.find((e) => {
49
+ if (e.type !== "message")
50
+ return false;
51
+ const role = messageOf(e)?.role;
52
+ return role === "user" || role === "assistant";
53
+ }) ?? childless[0];
54
+ if (!leaf)
55
+ return entries;
56
+ const walk = (e, acc, seen) => {
57
+ if (!e || typeof e.id !== "string" || seen.has(e.id))
58
+ return acc;
59
+ return walk(typeof e.parentId === "string" ? byId.get(e.parentId) : undefined, [e, ...acc], new Set([...seen, e.id]));
60
+ };
61
+ const chain = walk(leaf, [], new Set());
62
+ return chain.length > 0 ? chain : entries;
63
+ };
64
+ // Parse one pi session file (~/.pi/agent/sessions/<munged-cwd>/
65
+ // <timestamp>_<uuid>.jsonl) into the normalized transcript shape. The first
66
+ // line is a {type:"session"} header carrying the session id and cwd; entry
67
+ // lines wrap AgentMessages ({type:"message", id, parentId, message}). Only
68
+ // user/assistant messages are conversation text — toolResult/bashExecution
69
+ // are tool chatter, and custom-role messages are extension-injected context
70
+ // (glen's own per-turn recall arrives as customType "glen-context"; importing
71
+ // it would feed glen's output back in as memory). Tolerant by design: unknown
72
+ // entry types, missing fields, and unparseable lines are skipped, never fatal.
73
+ const parsePiTranscript = (lines, fallbackSessionId) => {
74
+ const entries = lines.map(parseLine).filter((e) => e !== null);
75
+ const header = entries.find((e) => e.type === "session");
76
+ const conversation = activeBranch(entries.filter((e) => e.type !== "session")).filter((e) => {
77
+ if (e.type !== "message")
78
+ return false;
79
+ const role = messageOf(e)?.role;
80
+ return role === "user" || role === "assistant";
81
+ });
82
+ const messages = [];
83
+ for (const e of conversation) {
84
+ const message = messageOf(e);
85
+ if (!message)
86
+ continue;
87
+ if (message.role === "user") {
88
+ messages.push({ role: "user", text: textOf(message.content) });
89
+ }
90
+ else {
91
+ messages.push({ role: "assistant", text: textOf(message.content) });
92
+ }
93
+ }
94
+ if (messages.every((m) => m.text.trim() === ""))
95
+ return null;
96
+ // Assistant messages carry the model that produced them; the last one wins
97
+ // (the model can change mid-session via /model).
98
+ const lastModel = [...conversation]
99
+ .reverse()
100
+ .map((e) => messageOf(e)?.model)
101
+ .find((m) => typeof m === "string");
102
+ return {
103
+ sessionId: (typeof header?.id === "string" ? header.id : undefined) ??
104
+ fallbackSessionId,
105
+ agent: "pi",
106
+ cwd: typeof header?.cwd === "string" ? header.cwd : undefined,
107
+ branch: undefined,
108
+ model: lastModel,
109
+ messages,
110
+ };
111
+ };
112
+ export { parsePiTranscript };
113
+ //# sourceMappingURL=parse-pi-transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-pi-transcript.js","sourceRoot":"","sources":["../../src/_utils/parse-pi-transcript.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  type PluginStatus = "installed" | "not-installed" | "unknown";
2
- declare const glenPluginStatus: (agentBin: "claude" | "codex") => PluginStatus;
2
+ declare const glenPluginStatus: (agentBin: "claude" | "codex" | "pi") => PluginStatus;
3
3
  export { glenPluginStatus };
4
4
  export type { PluginStatus };
@@ -1,3 +1,6 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
1
4
  import { findBin } from "./find-bin.js";
2
5
  import { runBin } from "./run-bin.js";
3
6
  // A line whose first token is the glen plugin: claude lists `❯ glen@glen`
@@ -7,10 +10,51 @@ import { runBin } from "./run-bin.js";
7
10
  // name, so `foo@glen`, `glenda`, or a description merely mentioning glen
8
11
  // never false-positives.
9
12
  const GLEN_PLUGIN_LINE = /^[\s>❯•*-]*glen(@\S+)?(\s|$)/im;
10
- // Detects whether the glen plugin is installed for an agent by parsing
11
- // `<agent> plugin list` output. "unknown" (agent missing or list failed)
13
+ // Pi settings path (GLEN_PI_SETTINGS_PATH env var is for test overrides only).
14
+ const piSettingsPath = () => process.env.GLEN_PI_SETTINGS_PATH ??
15
+ join(homedir(), ".pi", "agent", "settings.json");
16
+ // Pi has no `plugin list` — `pi install` records the package in the `packages`
17
+ // array of ~/.pi/agent/settings.json (string or `{ source }` object entries),
18
+ // so that file is the source of truth. A missing file means pi has no packages
19
+ // at all (fresh install) → not-installed; an unreadable/corrupt file → unknown
20
+ // (callers fall back to attempting an install, which is idempotent).
21
+ const piPluginStatus = () => {
22
+ const raw = (() => {
23
+ try {
24
+ return readFileSync(piSettingsPath(), "utf8");
25
+ }
26
+ catch (e) {
27
+ return e.code === "ENOENT" ? "" : null;
28
+ }
29
+ })();
30
+ if (raw === null)
31
+ return "unknown";
32
+ if (raw === "")
33
+ return "not-installed";
34
+ try {
35
+ const parsed = JSON.parse(raw);
36
+ const packages = Array.isArray(parsed.packages) ? parsed.packages : [];
37
+ const registered = packages.some((entry) => {
38
+ const source = typeof entry === "string"
39
+ ? entry
40
+ : entry !== null && typeof entry === "object"
41
+ ? entry.source
42
+ : undefined;
43
+ return typeof source === "string" && source.includes("glen-pi-plugin");
44
+ });
45
+ return registered ? "installed" : "not-installed";
46
+ }
47
+ catch {
48
+ return "unknown";
49
+ }
50
+ };
51
+ // Detects whether the glen plugin is installed for an agent — by parsing
52
+ // `<agent> plugin list` output (claude/codex), or by reading pi's settings
53
+ // file (pi has no plugin-list CLI). "unknown" (agent missing or check failed)
12
54
  // lets callers fall back to attempting an install.
13
55
  const glenPluginStatus = (agentBin) => {
56
+ if (agentBin === "pi")
57
+ return piPluginStatus();
14
58
  const bin = findBin(agentBin);
15
59
  if (!bin)
16
60
  return "unknown";
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-status.js","sourceRoot":"","sources":["../../src/_utils/plugin-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAItC,0EAA0E;AAC1E,uEAAuE;AACvE,4EAA4E;AAC5E,6EAA6E;AAC7E,yEAAyE;AACzE,yBAAyB;AACzB,MAAM,gBAAgB,GAAG,gCAAgC,CAAC;AAE1D,uEAAuE;AACvE,yEAAyE;AACzE,mDAAmD;AACnD,MAAM,gBAAgB,GAAG,CAAC,QAA4B,EAAgB,EAAE;IACtE,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,CAAC,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAC5B,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC;AAC/E,CAAC,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"plugin-status.js","sourceRoot":"","sources":["../../src/_utils/plugin-status.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ type TranscriptMessage = {
4
4
  };
5
5
  type ParsedTranscript = {
6
6
  readonly sessionId: string;
7
- readonly agent: "claude-code" | "codex" | "cursor";
7
+ readonly agent: "claude-code" | "codex" | "cursor" | "pi";
8
8
  readonly cwd: string | undefined;
9
9
  readonly branch: string | undefined;
10
10
  readonly model: string | undefined;