@halyard/cli 0.1.2 → 0.2.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.
Files changed (141) hide show
  1. package/README.md +88 -1
  2. package/dist/cli.js +27 -4
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/api-keys.d.ts +3 -0
  5. package/dist/commands/api-keys.d.ts.map +1 -0
  6. package/dist/commands/api-keys.js +90 -0
  7. package/dist/commands/api-keys.js.map +1 -0
  8. package/dist/commands/hook.d.ts +6 -0
  9. package/dist/commands/hook.d.ts.map +1 -0
  10. package/dist/commands/hook.js +106 -0
  11. package/dist/commands/hook.js.map +1 -0
  12. package/dist/commands/login.d.ts +17 -0
  13. package/dist/commands/login.d.ts.map +1 -1
  14. package/dist/commands/login.js +111 -14
  15. package/dist/commands/login.js.map +1 -1
  16. package/dist/commands/orgs.d.ts +3 -0
  17. package/dist/commands/orgs.d.ts.map +1 -0
  18. package/dist/commands/orgs.js +102 -0
  19. package/dist/commands/orgs.js.map +1 -0
  20. package/dist/commands/push.d.ts.map +1 -1
  21. package/dist/commands/push.js +29 -6
  22. package/dist/commands/push.js.map +1 -1
  23. package/dist/commands/sessions.d.ts +3 -0
  24. package/dist/commands/sessions.d.ts.map +1 -0
  25. package/dist/commands/sessions.js +139 -0
  26. package/dist/commands/sessions.js.map +1 -0
  27. package/dist/commands/setup.d.ts.map +1 -1
  28. package/dist/commands/setup.js +28 -3
  29. package/dist/commands/setup.js.map +1 -1
  30. package/dist/commands/skills.d.ts +12 -0
  31. package/dist/commands/skills.d.ts.map +1 -0
  32. package/dist/commands/skills.js +171 -0
  33. package/dist/commands/skills.js.map +1 -0
  34. package/dist/commands/sync.d.ts.map +1 -1
  35. package/dist/commands/sync.js +51 -49
  36. package/dist/commands/sync.js.map +1 -1
  37. package/dist/commands/users.d.ts +13 -0
  38. package/dist/commands/users.d.ts.map +1 -0
  39. package/dist/commands/users.js +205 -0
  40. package/dist/commands/users.js.map +1 -0
  41. package/dist/commands/whoami.d.ts +21 -0
  42. package/dist/commands/whoami.d.ts.map +1 -0
  43. package/dist/commands/whoami.js +77 -0
  44. package/dist/commands/whoami.js.map +1 -0
  45. package/dist/lib/api-client.d.ts +64 -2
  46. package/dist/lib/api-client.d.ts.map +1 -1
  47. package/dist/lib/api-client.js +32 -7
  48. package/dist/lib/api-client.js.map +1 -1
  49. package/dist/lib/auth.d.ts +42 -6
  50. package/dist/lib/auth.d.ts.map +1 -1
  51. package/dist/lib/auth.js +101 -27
  52. package/dist/lib/auth.js.map +1 -1
  53. package/dist/lib/config-files.d.ts +6 -0
  54. package/dist/lib/config-files.d.ts.map +1 -0
  55. package/dist/lib/config-files.js +27 -0
  56. package/dist/lib/config-files.js.map +1 -0
  57. package/dist/lib/config.d.ts +13 -7
  58. package/dist/lib/config.d.ts.map +1 -1
  59. package/dist/lib/config.js +22 -8
  60. package/dist/lib/config.js.map +1 -1
  61. package/dist/lib/copilot-export.d.ts +31 -0
  62. package/dist/lib/copilot-export.d.ts.map +1 -0
  63. package/dist/lib/copilot-export.js +129 -0
  64. package/dist/lib/copilot-export.js.map +1 -0
  65. package/dist/lib/discovery.d.ts +60 -2
  66. package/dist/lib/discovery.d.ts.map +1 -1
  67. package/dist/lib/discovery.js +187 -15
  68. package/dist/lib/discovery.js.map +1 -1
  69. package/dist/lib/hook-discovery.d.ts +43 -0
  70. package/dist/lib/hook-discovery.d.ts.map +1 -0
  71. package/dist/lib/hook-discovery.js +90 -0
  72. package/dist/lib/hook-discovery.js.map +1 -0
  73. package/dist/lib/hook-input.d.ts +36 -0
  74. package/dist/lib/hook-input.d.ts.map +1 -0
  75. package/dist/lib/hook-input.js +161 -0
  76. package/dist/lib/hook-input.js.map +1 -0
  77. package/dist/lib/hook-runner.d.ts +48 -0
  78. package/dist/lib/hook-runner.d.ts.map +1 -0
  79. package/dist/lib/hook-runner.js +306 -0
  80. package/dist/lib/hook-runner.js.map +1 -0
  81. package/dist/lib/http.d.ts +18 -0
  82. package/dist/lib/http.d.ts.map +1 -0
  83. package/dist/lib/http.js +54 -0
  84. package/dist/lib/http.js.map +1 -0
  85. package/dist/lib/opencode-export.d.ts +22 -0
  86. package/dist/lib/opencode-export.d.ts.map +1 -0
  87. package/dist/lib/opencode-export.js +53 -0
  88. package/dist/lib/opencode-export.js.map +1 -0
  89. package/dist/lib/output.d.ts +27 -0
  90. package/dist/lib/output.d.ts.map +1 -0
  91. package/dist/lib/output.js +74 -0
  92. package/dist/lib/output.js.map +1 -0
  93. package/dist/lib/preflight.d.ts +35 -0
  94. package/dist/lib/preflight.d.ts.map +1 -0
  95. package/dist/lib/preflight.js +54 -0
  96. package/dist/lib/preflight.js.map +1 -0
  97. package/dist/lib/repo-binding.d.ts +43 -0
  98. package/dist/lib/repo-binding.d.ts.map +1 -0
  99. package/dist/lib/repo-binding.js +158 -0
  100. package/dist/lib/repo-binding.js.map +1 -0
  101. package/dist/lib/repo-identity.d.ts +29 -0
  102. package/dist/lib/repo-identity.d.ts.map +1 -0
  103. package/dist/lib/repo-identity.js +113 -0
  104. package/dist/lib/repo-identity.js.map +1 -0
  105. package/dist/lib/setup-hooks.d.ts +41 -0
  106. package/dist/lib/setup-hooks.d.ts.map +1 -0
  107. package/dist/lib/setup-hooks.js +276 -0
  108. package/dist/lib/setup-hooks.js.map +1 -0
  109. package/dist/lib/setup.d.ts +4 -1
  110. package/dist/lib/setup.d.ts.map +1 -1
  111. package/dist/lib/setup.js +20 -31
  112. package/dist/lib/setup.js.map +1 -1
  113. package/dist/lib/skill-batches.d.ts +16 -0
  114. package/dist/lib/skill-batches.d.ts.map +1 -0
  115. package/dist/lib/skill-batches.js +35 -0
  116. package/dist/lib/skill-batches.js.map +1 -0
  117. package/dist/lib/skill-files.d.ts +4 -0
  118. package/dist/lib/skill-files.d.ts.map +1 -0
  119. package/dist/lib/skill-files.js +36 -0
  120. package/dist/lib/skill-files.js.map +1 -0
  121. package/dist/lib/skill-fingerprint.d.ts +55 -0
  122. package/dist/lib/skill-fingerprint.d.ts.map +1 -0
  123. package/dist/lib/skill-fingerprint.js +204 -0
  124. package/dist/lib/skill-fingerprint.js.map +1 -0
  125. package/dist/lib/skills-discovery.d.ts +57 -0
  126. package/dist/lib/skills-discovery.d.ts.map +1 -0
  127. package/dist/lib/skills-discovery.js +157 -0
  128. package/dist/lib/skills-discovery.js.map +1 -0
  129. package/dist/lib/skills-sync.d.ts +66 -0
  130. package/dist/lib/skills-sync.d.ts.map +1 -0
  131. package/dist/lib/skills-sync.js +251 -0
  132. package/dist/lib/skills-sync.js.map +1 -0
  133. package/dist/lib/sync-runner.d.ts +56 -0
  134. package/dist/lib/sync-runner.d.ts.map +1 -0
  135. package/dist/lib/sync-runner.js +106 -0
  136. package/dist/lib/sync-runner.js.map +1 -0
  137. package/dist/lib/sync-state.d.ts +36 -6
  138. package/dist/lib/sync-state.d.ts.map +1 -1
  139. package/dist/lib/sync-state.js +41 -11
  140. package/dist/lib/sync-state.js.map +1 -1
  141. package/package.json +10 -5
@@ -0,0 +1,31 @@
1
+ /**
2
+ * GitHub Copilot CLI integration.
3
+ *
4
+ * Copilot CLI (verified against v1.0.82) keeps all sessions in one shared
5
+ * SQLite store, `~/.copilot/session-store.db`:
6
+ *
7
+ * - `sessions` (id, cwd, repository, branch, created_at, updated_at)
8
+ * - `turns` (session_id, turn_index, user_message, assistant_response, timestamp)
9
+ * - `assistant_usage_events` (session_id, model, input_tokens, output_tokens,
10
+ * cache_read_tokens, cache_write_tokens, reasoning_tokens, ...)
11
+ * - `forge_trajectory_events` (session_id, event_type, command, exit_code, ...)
12
+ *
13
+ * Since there is no per-session file to upload, each session is exported as
14
+ * a versioned JSONL bundle the server-side parser understands
15
+ * (`packages/queue/src/lib/session-parsers/copilot.ts`): one
16
+ * `halyard_copilot_session` meta line, then `turn` / `usage` / `trajectory`
17
+ * records.
18
+ *
19
+ * The store is read via the built-in `node:sqlite` module (Node ≥ 22.13,
20
+ * read-only — no native dependency). On older Nodes, or when anything about
21
+ * the store is unreadable, discovery degrades to "no sessions" rather than
22
+ * breaking `halyard sync` for other providers.
23
+ */
24
+ export declare const COPILOT_BUNDLE_VERSION = 1;
25
+ export interface CopilotSessionRef {
26
+ id: string;
27
+ updatedAt: string;
28
+ }
29
+ export declare function listCopilotSessions(): CopilotSessionRef[];
30
+ export declare function buildCopilotBundle(sessionId: string): Buffer;
31
+ //# sourceMappingURL=copilot-export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-export.d.ts","sourceRoot":"","sources":["../../src/lib/copilot-export.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,eAAO,MAAM,sBAAsB,IAAI,CAAA;AAEvC,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;CAClB;AA2BD,wBAAgB,mBAAmB,IAAI,iBAAiB,EAAE,CAqBzD;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAmD5D"}
@@ -0,0 +1,129 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ /**
5
+ * GitHub Copilot CLI integration.
6
+ *
7
+ * Copilot CLI (verified against v1.0.82) keeps all sessions in one shared
8
+ * SQLite store, `~/.copilot/session-store.db`:
9
+ *
10
+ * - `sessions` (id, cwd, repository, branch, created_at, updated_at)
11
+ * - `turns` (session_id, turn_index, user_message, assistant_response, timestamp)
12
+ * - `assistant_usage_events` (session_id, model, input_tokens, output_tokens,
13
+ * cache_read_tokens, cache_write_tokens, reasoning_tokens, ...)
14
+ * - `forge_trajectory_events` (session_id, event_type, command, exit_code, ...)
15
+ *
16
+ * Since there is no per-session file to upload, each session is exported as
17
+ * a versioned JSONL bundle the server-side parser understands
18
+ * (`packages/queue/src/lib/session-parsers/copilot.ts`): one
19
+ * `halyard_copilot_session` meta line, then `turn` / `usage` / `trajectory`
20
+ * records.
21
+ *
22
+ * The store is read via the built-in `node:sqlite` module (Node ≥ 22.13,
23
+ * read-only — no native dependency). On older Nodes, or when anything about
24
+ * the store is unreadable, discovery degrades to "no sessions" rather than
25
+ * breaking `halyard sync` for other providers.
26
+ */
27
+ export const COPILOT_BUNDLE_VERSION = 1;
28
+ function copilotDir() {
29
+ return process.env.COPILOT_DIR ?? join(homedir(), '.copilot');
30
+ }
31
+ function openStore() {
32
+ const dbPath = join(copilotDir(), 'session-store.db');
33
+ if (!existsSync(dbPath))
34
+ return null;
35
+ try {
36
+ // node:sqlite is unflagged from Node 22.13; getBuiltinModule avoids a
37
+ // hard import so older runtimes degrade gracefully.
38
+ const sqlite = process.getBuiltinModule?.('node:sqlite');
39
+ if (!sqlite?.DatabaseSync)
40
+ return null;
41
+ return new sqlite.DatabaseSync(dbPath, { readOnly: true });
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ export function listCopilotSessions() {
48
+ const db = openStore();
49
+ if (!db)
50
+ return [];
51
+ try {
52
+ // Only sessions with actual conversation or usage activity — Copilot
53
+ // creates empty session rows for launches that never reach a turn.
54
+ const rows = db
55
+ .prepare(`SELECT s.id AS id, s.updated_at AS updated_at FROM sessions s
56
+ WHERE EXISTS (SELECT 1 FROM turns t WHERE t.session_id = s.id)
57
+ OR EXISTS (SELECT 1 FROM assistant_usage_events u WHERE u.session_id = s.id)`)
58
+ .all();
59
+ return rows
60
+ .filter((r) => typeof r.id === 'string')
61
+ .map((r) => ({ id: r.id, updatedAt: String(r.updated_at ?? '') }));
62
+ }
63
+ catch {
64
+ return [];
65
+ }
66
+ finally {
67
+ db.close();
68
+ }
69
+ }
70
+ export function buildCopilotBundle(sessionId) {
71
+ const db = openStore();
72
+ if (!db) {
73
+ throw new Error('Copilot session store is not readable (requires Node >= 22.13)');
74
+ }
75
+ try {
76
+ const session = db.prepare('SELECT * FROM sessions WHERE id = ?').all(sessionId)[0];
77
+ if (!session)
78
+ throw new Error(`Copilot session not found: ${sessionId}`);
79
+ const lines = [
80
+ JSON.stringify({
81
+ type: 'halyard_copilot_session',
82
+ bundleVersion: COPILOT_BUNDLE_VERSION,
83
+ session,
84
+ workspace: readWorkspaceYaml(sessionId),
85
+ }),
86
+ ];
87
+ const push = (type, rows) => {
88
+ for (const row of rows)
89
+ lines.push(JSON.stringify({ type, ...row }));
90
+ };
91
+ push('turn', db
92
+ .prepare('SELECT turn_index, user_message, assistant_response, timestamp FROM turns WHERE session_id = ? ORDER BY turn_index')
93
+ .all(sessionId));
94
+ push('usage', db
95
+ .prepare(`SELECT turn_index, model, input_tokens, output_tokens, cache_read_tokens,
96
+ cache_write_tokens, reasoning_tokens, duration_ms, created_at
97
+ FROM assistant_usage_events WHERE session_id = ? ORDER BY id`)
98
+ .all(sessionId));
99
+ push('trajectory', db
100
+ .prepare(`SELECT tool_call_id, turn_index, event_type, command, exit_code, created_at
101
+ FROM forge_trajectory_events WHERE session_id = ? ORDER BY id`)
102
+ .all(sessionId));
103
+ return Buffer.from(`${lines.join('\n')}\n`);
104
+ }
105
+ finally {
106
+ db.close();
107
+ }
108
+ }
109
+ /**
110
+ * Best-effort read of the per-session workspace.yaml (flat `key: value`
111
+ * lines only — no YAML dependency needed for this shape).
112
+ */
113
+ function readWorkspaceYaml(sessionId) {
114
+ const path = join(copilotDir(), 'session-state', sessionId, 'workspace.yaml');
115
+ try {
116
+ const parsed = {};
117
+ for (const line of readFileSync(path, 'utf-8').split('\n')) {
118
+ const idx = line.indexOf(': ');
119
+ if (idx <= 0)
120
+ continue;
121
+ parsed[line.slice(0, idx).trim()] = line.slice(idx + 2).trim();
122
+ }
123
+ return parsed;
124
+ }
125
+ catch {
126
+ return null;
127
+ }
128
+ }
129
+ //# sourceMappingURL=copilot-export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-export.js","sourceRoot":"","sources":["../../src/lib/copilot-export.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,32 @@
1
+ export type SessionProvider = 'claude' | 'codex' | 'gemini' | 'opencode' | 'copilot';
2
+ export declare const SESSION_PROVIDERS: SessionProvider[];
1
3
  export interface DiscoveredSession {
2
- provider: 'claude' | 'codex';
4
+ provider: SessionProvider;
5
+ /**
6
+ * Stable sync-state key. A real file path for file-backed providers
7
+ * (claude/codex/gemini); a `provider://sessionId` pseudo-path for
8
+ * store-backed providers (opencode/copilot) whose sessions live in a
9
+ * shared database rather than one file.
10
+ */
3
11
  filePath: string;
4
12
  sessionId: string;
5
13
  sizeBytes: number;
14
+ /**
15
+ * Working directory the session ran in, extracted from the log head.
16
+ * Only populated for providers whose log format is known to carry it
17
+ * (claude, codex); absent sessions count as unresolved in scoped sync.
18
+ */
19
+ cwd?: string;
20
+ /**
21
+ * Change marker for store-backed sessions — hashed in place of file
22
+ * contents so sync can skip unchanged sessions without exporting them.
23
+ * Absent for file-backed sessions (their bytes are hashed directly).
24
+ */
25
+ freshness?: string;
6
26
  }
7
27
  /**
8
28
  * Discover Claude Code session log files.
9
- * Claude Code stores sessions in ~/.claude/projects/<project-hash>/sessions/
29
+ * Claude Code stores sessions in ~/.claude/projects/<project-hash>/
10
30
  * Session files are JSONL format.
11
31
  */
12
32
  export declare function discoverClaudeSessions(): DiscoveredSession[];
@@ -15,8 +35,46 @@ export declare function discoverClaudeSessions(): DiscoveredSession[];
15
35
  * Codex stores sessions in ~/.codex/sessions/<yyyy>/<mm>/<dd>/rollout-*.jsonl
16
36
  */
17
37
  export declare function discoverCodexSessions(): DiscoveredSession[];
38
+ /**
39
+ * Discover Gemini CLI chat session files.
40
+ * Gemini CLI stores sessions in ~/.gemini/tmp/<project>/chats/session-*.jsonl
41
+ * (legacy sessions are single-JSON `.json` files; subagent sessions live in
42
+ * chats/<parent-session-id>/ subdirectories).
43
+ */
44
+ export declare function discoverGeminiSessions(): DiscoveredSession[];
45
+ /**
46
+ * Discover OpenCode sessions. OpenCode keeps everything in a SQLite
47
+ * database; sessions are listed via the `opencode` CLI itself and exported
48
+ * one at a time at upload time (see loadSessionContent).
49
+ */
50
+ export declare function discoverOpencodeSessions(): DiscoveredSession[];
51
+ /**
52
+ * Discover GitHub Copilot CLI sessions. Copilot CLI keeps all sessions in
53
+ * one shared SQLite store (~/.copilot/session-store.db); each session is
54
+ * exported as a JSONL bundle at upload time (see loadSessionContent).
55
+ */
56
+ export declare function discoverCopilotSessions(): DiscoveredSession[];
18
57
  /**
19
58
  * Auto-detect which providers have session files available.
20
59
  */
21
60
  export declare function discoverAllSessions(providerFilter?: string): DiscoveredSession[];
61
+ /**
62
+ * Materialize the bytes to upload for a discovered session: the file itself
63
+ * for file-backed providers, or a synthesized export for store-backed ones.
64
+ */
65
+ export declare function loadSessionContent(session: DiscoveredSession): Promise<Buffer>;
66
+ /** The name the ingest endpoint stores for the uploaded blob. */
67
+ export declare function uploadFileName(session: DiscoveredSession): string;
68
+ /**
69
+ * Claude session logs: the first records are often non-cwd entries
70
+ * (type:"queue-operation", "last-prompt", ...); a record carrying a `cwd`
71
+ * string reliably appears within the first few lines. Scan up to
72
+ * MAX_HEAD_LINES JSON lines and take the first `cwd` found.
73
+ */
74
+ export declare function extractClaudeCwd(head: string): string | undefined;
75
+ /**
76
+ * Codex session logs: the first line is a session_meta record with the cwd at
77
+ * `payload.cwd` (older formats used a top-level `cwd`).
78
+ */
79
+ export declare function extractCodexCwd(firstLine: string): string | undefined;
22
80
  //# sourceMappingURL=discovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/lib/discovery.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,iBAAiB,EAAE,CAoB5D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,iBAAiB,EAAE,CAO3D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAYhF"}
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/lib/discovery.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAA;AAEpF,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAM9C,CAAA;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,eAAe,CAAA;IACzB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAOD;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,iBAAiB,EAAE,CAoB5D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,iBAAiB,EAAE,CAO3D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,IAAI,iBAAiB,EAAE,CAmB5D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,iBAAiB,EAAE,CAQ9D;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,iBAAiB,EAAE,CAQ7D;AAUD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAOhF;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAQpF;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAIjE;AAsDD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYjE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWrE"}
@@ -1,9 +1,22 @@
1
1
  import { homedir } from 'node:os';
2
- import { join, basename } from 'node:path';
3
- import { readdirSync, statSync, existsSync } from 'node:fs';
2
+ import { join, basename, extname } from 'node:path';
3
+ import { readdirSync, readFileSync, statSync, existsSync, openSync, readSync, closeSync, } from 'node:fs';
4
+ import { buildCopilotBundle, listCopilotSessions } from './copilot-export.js';
5
+ import { exportOpencodeSession, listOpencodeSessions } from './opencode-export.js';
6
+ export const SESSION_PROVIDERS = [
7
+ 'claude',
8
+ 'codex',
9
+ 'gemini',
10
+ 'opencode',
11
+ 'copilot',
12
+ ];
13
+ /** How much of a session file to read when looking for the cwd record. */
14
+ const HEAD_BYTES = 64 * 1024;
15
+ /** How many head lines to scan for a Claude cwd record. */
16
+ const MAX_HEAD_LINES = 50;
4
17
  /**
5
18
  * Discover Claude Code session log files.
6
- * Claude Code stores sessions in ~/.claude/projects/<project-hash>/sessions/
19
+ * Claude Code stores sessions in ~/.claude/projects/<project-hash>/
7
20
  * Session files are JSONL format.
8
21
  */
9
22
  export function discoverClaudeSessions() {
@@ -18,7 +31,7 @@ export function discoverClaudeSessions() {
18
31
  if (!statSync(projectPath).isDirectory())
19
32
  continue;
20
33
  // Look for JSONL files directly in project dir and in sessions subdirs
21
- walkForJsonl(projectPath, 'claude', sessions, 0);
34
+ walkForSessionFiles(projectPath, 'claude', ['.jsonl'], sessions, 0);
22
35
  }
23
36
  }
24
37
  catch {
@@ -35,24 +48,108 @@ export function discoverCodexSessions() {
35
48
  if (!existsSync(codexDir))
36
49
  return [];
37
50
  const sessions = [];
38
- walkForJsonl(codexDir, 'codex', sessions, 0);
51
+ walkForSessionFiles(codexDir, 'codex', ['.jsonl'], sessions, 0);
39
52
  return sessions;
40
53
  }
54
+ /**
55
+ * Discover Gemini CLI chat session files.
56
+ * Gemini CLI stores sessions in ~/.gemini/tmp/<project>/chats/session-*.jsonl
57
+ * (legacy sessions are single-JSON `.json` files; subagent sessions live in
58
+ * chats/<parent-session-id>/ subdirectories).
59
+ */
60
+ export function discoverGeminiSessions() {
61
+ const geminiTmp = join(homedir(), '.gemini', 'tmp');
62
+ if (!existsSync(geminiTmp))
63
+ return [];
64
+ const sessions = [];
65
+ try {
66
+ for (const project of readdirSync(geminiTmp)) {
67
+ const chatsDir = join(geminiTmp, project, 'chats');
68
+ try {
69
+ if (!statSync(chatsDir).isDirectory())
70
+ continue;
71
+ }
72
+ catch {
73
+ continue;
74
+ }
75
+ walkForSessionFiles(chatsDir, 'gemini', ['.jsonl', '.json'], sessions, 0);
76
+ }
77
+ }
78
+ catch {
79
+ // Permission errors - silently skip
80
+ }
81
+ return sessions;
82
+ }
83
+ /**
84
+ * Discover OpenCode sessions. OpenCode keeps everything in a SQLite
85
+ * database; sessions are listed via the `opencode` CLI itself and exported
86
+ * one at a time at upload time (see loadSessionContent).
87
+ */
88
+ export function discoverOpencodeSessions() {
89
+ return listOpencodeSessions().map((s) => ({
90
+ provider: 'opencode',
91
+ filePath: `opencode://${s.id}`,
92
+ sessionId: s.id,
93
+ sizeBytes: 0,
94
+ freshness: `${s.id}:${s.timeUpdated}`,
95
+ }));
96
+ }
97
+ /**
98
+ * Discover GitHub Copilot CLI sessions. Copilot CLI keeps all sessions in
99
+ * one shared SQLite store (~/.copilot/session-store.db); each session is
100
+ * exported as a JSONL bundle at upload time (see loadSessionContent).
101
+ */
102
+ export function discoverCopilotSessions() {
103
+ return listCopilotSessions().map((s) => ({
104
+ provider: 'copilot',
105
+ filePath: `copilot://${s.id}`,
106
+ sessionId: s.id,
107
+ sizeBytes: 0,
108
+ freshness: `${s.id}:${s.updatedAt}`,
109
+ }));
110
+ }
111
+ const DISCOVERERS = {
112
+ claude: discoverClaudeSessions,
113
+ codex: discoverCodexSessions,
114
+ gemini: discoverGeminiSessions,
115
+ opencode: discoverOpencodeSessions,
116
+ copilot: discoverCopilotSessions,
117
+ };
41
118
  /**
42
119
  * Auto-detect which providers have session files available.
43
120
  */
44
121
  export function discoverAllSessions(providerFilter) {
45
122
  const sessions = [];
46
- if (!providerFilter || providerFilter === 'claude') {
47
- sessions.push(...discoverClaudeSessions());
48
- }
49
- if (!providerFilter || providerFilter === 'codex') {
50
- sessions.push(...discoverCodexSessions());
123
+ for (const provider of SESSION_PROVIDERS) {
124
+ if (providerFilter && providerFilter !== provider)
125
+ continue;
126
+ sessions.push(...DISCOVERERS[provider]());
51
127
  }
52
128
  return sessions;
53
129
  }
54
- /** Recursively walk a directory for .jsonl files, with a max depth. */
55
- function walkForJsonl(dir, provider, results, depth) {
130
+ /**
131
+ * Materialize the bytes to upload for a discovered session: the file itself
132
+ * for file-backed providers, or a synthesized export for store-backed ones.
133
+ */
134
+ export async function loadSessionContent(session) {
135
+ if (session.provider === 'opencode') {
136
+ return exportOpencodeSession(session.sessionId);
137
+ }
138
+ if (session.provider === 'copilot') {
139
+ return buildCopilotBundle(session.sessionId);
140
+ }
141
+ return readFileSync(session.filePath);
142
+ }
143
+ /** The name the ingest endpoint stores for the uploaded blob. */
144
+ export function uploadFileName(session) {
145
+ if (session.provider === 'opencode')
146
+ return `${session.sessionId}.json`;
147
+ if (session.provider === 'copilot')
148
+ return `${session.sessionId}.jsonl`;
149
+ return basename(session.filePath);
150
+ }
151
+ /** Recursively walk a directory for session files, with a max depth. */
152
+ function walkForSessionFiles(dir, provider, extensions, results, depth) {
56
153
  if (depth > 3)
57
154
  return; // Don't recurse too deep
58
155
  try {
@@ -62,14 +159,15 @@ function walkForJsonl(dir, provider, results, depth) {
62
159
  try {
63
160
  const stat = statSync(fullPath);
64
161
  if (stat.isDirectory()) {
65
- walkForJsonl(fullPath, provider, results, depth + 1);
162
+ walkForSessionFiles(fullPath, provider, extensions, results, depth + 1);
66
163
  }
67
- else if (entry.endsWith('.jsonl') && stat.size > 0) {
164
+ else if (extensions.includes(extname(entry)) && stat.size > 0) {
68
165
  results.push({
69
166
  provider,
70
167
  filePath: fullPath,
71
- sessionId: basename(entry, '.jsonl'),
168
+ sessionId: basename(entry, extname(entry)),
72
169
  sizeBytes: stat.size,
170
+ cwd: extractSessionCwd(fullPath, provider),
73
171
  });
74
172
  }
75
173
  }
@@ -82,4 +180,78 @@ function walkForJsonl(dir, provider, results, depth) {
82
180
  // Skip directories we can't read
83
181
  }
84
182
  }
183
+ /**
184
+ * Extract the session's working directory from the head of a log file.
185
+ * Only claude and codex formats are known to carry it; other providers
186
+ * return undefined (their sessions count as unresolved in scoped sync).
187
+ */
188
+ function extractSessionCwd(filePath, provider) {
189
+ if (provider !== 'claude' && provider !== 'codex')
190
+ return undefined;
191
+ const head = readFileHead(filePath);
192
+ if (head === null)
193
+ return undefined;
194
+ if (provider === 'codex') {
195
+ const firstLine = head.split('\n', 1)[0] ?? '';
196
+ return extractCodexCwd(firstLine);
197
+ }
198
+ return extractClaudeCwd(head);
199
+ }
200
+ /**
201
+ * Claude session logs: the first records are often non-cwd entries
202
+ * (type:"queue-operation", "last-prompt", ...); a record carrying a `cwd`
203
+ * string reliably appears within the first few lines. Scan up to
204
+ * MAX_HEAD_LINES JSON lines and take the first `cwd` found.
205
+ */
206
+ export function extractClaudeCwd(head) {
207
+ const lines = head.split('\n', MAX_HEAD_LINES);
208
+ for (const line of lines) {
209
+ if (!line.trim())
210
+ continue;
211
+ try {
212
+ const parsed = JSON.parse(line);
213
+ if (typeof parsed.cwd === 'string' && parsed.cwd.length > 0)
214
+ return parsed.cwd;
215
+ }
216
+ catch {
217
+ // Malformed (or truncated tail) line - keep scanning
218
+ }
219
+ }
220
+ return undefined;
221
+ }
222
+ /**
223
+ * Codex session logs: the first line is a session_meta record with the cwd at
224
+ * `payload.cwd` (older formats used a top-level `cwd`).
225
+ */
226
+ export function extractCodexCwd(firstLine) {
227
+ try {
228
+ const parsed = JSON.parse(firstLine);
229
+ if (typeof parsed.payload?.cwd === 'string' && parsed.payload.cwd.length > 0) {
230
+ return parsed.payload.cwd;
231
+ }
232
+ if (typeof parsed.cwd === 'string' && parsed.cwd.length > 0)
233
+ return parsed.cwd;
234
+ }
235
+ catch {
236
+ // Malformed first line
237
+ }
238
+ return undefined;
239
+ }
240
+ /** Read up to HEAD_BYTES from the start of a file without loading the rest. */
241
+ function readFileHead(filePath) {
242
+ try {
243
+ const fd = openSync(filePath, 'r');
244
+ try {
245
+ const buffer = Buffer.alloc(HEAD_BYTES);
246
+ const bytesRead = readSync(fd, buffer, 0, HEAD_BYTES, 0);
247
+ return buffer.toString('utf-8', 0, bytesRead);
248
+ }
249
+ finally {
250
+ closeSync(fd);
251
+ }
252
+ }
253
+ catch {
254
+ return null;
255
+ }
256
+ }
85
257
  //# sourceMappingURL=discovery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/lib/discovery.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/lib/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { type HookClient, type HookEvent } from './hook-input.js';
2
+ /**
3
+ * What `halyard hook` uploads for a client when the payload carries no
4
+ * transcript path. Claude and Codex logs record their cwd, so their sweeps go
5
+ * through the repo-scoped sync pipeline (`sync-runner`), which resolves each
6
+ * session's cwd to a repo identity. The clients below have no cwd in their
7
+ * transcripts, so they are matched by path or session id instead.
8
+ */
9
+ export interface SweepTarget {
10
+ file: string;
11
+ provider: string;
12
+ }
13
+ export interface SweepContext {
14
+ homeDir: string;
15
+ projectRoot: string;
16
+ sessionId: string;
17
+ transcriptPath: string;
18
+ event: HookEvent;
19
+ env: NodeJS.ProcessEnv;
20
+ }
21
+ export type SweepPlan = {
22
+ kind: 'files';
23
+ targets: SweepTarget[];
24
+ } | {
25
+ kind: 'sync';
26
+ provider: string;
27
+ /** Restrict to sessions whose cwd resolves to this repo (Claude, Codex). */
28
+ scoped: boolean;
29
+ };
30
+ /** Claude keeps subagent transcripts beside the main one:
31
+ * <dir>/<session>.jsonl + <dir>/<session>/subagents/agent-*.jsonl */
32
+ export declare function claudeSessionFiles(transcript: string): string[];
33
+ /** Rollout files end in the thread id: rollout-<timestamp>-<id>.jsonl */
34
+ export declare function findCodexRollout(homeDir: string, sessionId: string): string | null;
35
+ /** ~/.cursor/projects/<path-slug>/agent-transcripts/<conversation>/<conversation>.jsonl */
36
+ export declare function sweepCursor(ctx: SweepContext): SweepTarget[];
37
+ /** Grok Build keeps sessions under ~/.grok/sessions; the payload carries only
38
+ * the session id, so match on it. Layout is undocumented — best effort. */
39
+ export declare function sweepGrok(ctx: SweepContext): SweepTarget[];
40
+ /** Amp caches threads as T-<id>.json under ~/.local/share/amp (or AMP_DATA_DIR). */
41
+ export declare function sweepAmp(ctx: SweepContext): SweepTarget[];
42
+ export declare function sweepForClient(client: HookClient, ctx: SweepContext): SweepPlan;
43
+ //# sourceMappingURL=hook-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-discovery.d.ts","sourceRoot":"","sources":["../../src/lib/hook-discovery.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,iBAAiB,CAAA;AAExB;;;;;;GAMG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,KAAK,EAAE,SAAS,CAAA;IAChB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;CACvB;AAED,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,GACzC;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AAuBL;sEACsE;AACtE,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAW/D;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASlF;AAED,2FAA2F;AAC3F,wBAAgB,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,WAAW,EAAE,CAO5D;AAED;4EAC4E;AAC5E,wBAAgB,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,WAAW,EAAE,CAQ1D;AAED,oFAAoF;AACpF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,YAAY,GAAG,WAAW,EAAE,CAQzD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,GAAG,SAAS,CAe/E"}