agent-watch 1.0.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 (77) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +95 -0
  4. package/dist/cli-nMe9-VkJ.d.ts +1 -0
  5. package/dist/cli.cjs +770 -0
  6. package/dist/cli.cjs.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +771 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/commands/init.d.ts +2 -0
  12. package/dist/commands/init.d.ts.map +1 -0
  13. package/dist/commands/run.d.ts +5 -0
  14. package/dist/commands/run.d.ts.map +1 -0
  15. package/dist/config.d.ts +31 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/constants.d.ts +21 -0
  18. package/dist/constants.d.ts.map +1 -0
  19. package/dist/detect-BMnM34-m.cjs +177 -0
  20. package/dist/detect-BMnM34-m.cjs.map +1 -0
  21. package/dist/detect-BWGm1KGQ.js +122 -0
  22. package/dist/detect-BWGm1KGQ.js.map +1 -0
  23. package/dist/detect-B_DDBj5N.cjs +182 -0
  24. package/dist/detect-B_DDBj5N.cjs.map +1 -0
  25. package/dist/detect-CPW1RRIq.js +117 -0
  26. package/dist/detect-CPW1RRIq.js.map +1 -0
  27. package/dist/detect-Dii2e4wf.cjs +174 -0
  28. package/dist/detect-Dii2e4wf.cjs.map +1 -0
  29. package/dist/detect-Pkaqn3YG.js +120 -0
  30. package/dist/detect-Pkaqn3YG.js.map +1 -0
  31. package/dist/detect.d.ts +16 -0
  32. package/dist/detect.d.ts.map +1 -0
  33. package/dist/hooks.d.ts +13 -0
  34. package/dist/hooks.d.ts.map +1 -0
  35. package/dist/index-CXIlEXUx.d.ts +51 -0
  36. package/dist/index.cjs +13 -0
  37. package/dist/index.cjs.map +1 -0
  38. package/dist/index.d.cts +5 -0
  39. package/dist/index.d.ts +5 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +3 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/logger-BNjXChov.js +164 -0
  44. package/dist/logger-BNjXChov.js.map +1 -0
  45. package/dist/logger-CdAUnlsG.cjs +271 -0
  46. package/dist/logger-CdAUnlsG.cjs.map +1 -0
  47. package/dist/logger-hSIaaw_k.js +166 -0
  48. package/dist/logger-hSIaaw_k.js.map +1 -0
  49. package/dist/logger-oq2Z7oYf.cjs +269 -0
  50. package/dist/logger-oq2Z7oYf.cjs.map +1 -0
  51. package/dist/sessions-90kmJrQI.js +360 -0
  52. package/dist/sessions-90kmJrQI.js.map +1 -0
  53. package/dist/sessions-Bmk48zTI.js +311 -0
  54. package/dist/sessions-Bmk48zTI.js.map +1 -0
  55. package/dist/sessions-BpNk9YjU.cjs +431 -0
  56. package/dist/sessions-BpNk9YjU.cjs.map +1 -0
  57. package/dist/sessions-CkCQikpl.cjs +444 -0
  58. package/dist/sessions-CkCQikpl.cjs.map +1 -0
  59. package/dist/sessions-Cy-_zIh6.js +315 -0
  60. package/dist/sessions-Cy-_zIh6.js.map +1 -0
  61. package/dist/sessions-DZgPENb6.cjs +434 -0
  62. package/dist/sessions-DZgPENb6.cjs.map +1 -0
  63. package/dist/sessions-_HBb3nIW.cjs +495 -0
  64. package/dist/sessions-_HBb3nIW.cjs.map +1 -0
  65. package/dist/sessions-tBeR9gKG.js +308 -0
  66. package/dist/sessions-tBeR9gKG.js.map +1 -0
  67. package/dist/utils/copilot.d.ts +27 -0
  68. package/dist/utils/copilot.d.ts.map +1 -0
  69. package/dist/utils/git.d.ts +35 -0
  70. package/dist/utils/git.d.ts.map +1 -0
  71. package/dist/utils/gitignore.d.ts +5 -0
  72. package/dist/utils/gitignore.d.ts.map +1 -0
  73. package/dist/utils/logger.d.ts +14 -0
  74. package/dist/utils/logger.d.ts.map +1 -0
  75. package/dist/utils/sessions.d.ts +48 -0
  76. package/dist/utils/sessions.d.ts.map +1 -0
  77. package/package.json +79 -0
@@ -0,0 +1,444 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) {
13
+ __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ }
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+
27
+ //#endregion
28
+ let node_fs = require("node:fs");
29
+ let node_path = require("node:path");
30
+ let node_child_process = require("node:child_process");
31
+ let node_os = require("node:os");
32
+ let picocolors = require("picocolors");
33
+ picocolors = __toESM(picocolors);
34
+
35
+ //#region src/constants.ts
36
+ const KNOWN_AGENT_FILES = [
37
+ {
38
+ path: "AGENTS.md",
39
+ label: "AGENTS.md (Recommended)",
40
+ agent: "Generic"
41
+ },
42
+ {
43
+ path: "CLAUDE.md",
44
+ label: "CLAUDE.md (Claude Code)",
45
+ agent: "Claude Code"
46
+ },
47
+ {
48
+ path: ".github/copilot-instructions.md",
49
+ label: ".github/copilot-instructions.md (GitHub Copilot)",
50
+ agent: "GitHub Copilot"
51
+ },
52
+ {
53
+ path: ".cursor/rules",
54
+ label: ".cursor/rules (Cursor)",
55
+ agent: "Cursor"
56
+ },
57
+ {
58
+ path: ".windsurfrules",
59
+ label: ".windsurfrules (Windsurf)",
60
+ agent: "Windsurf"
61
+ },
62
+ {
63
+ path: ".clinerules",
64
+ label: ".clinerules (Cline)",
65
+ agent: "Cline"
66
+ }
67
+ ];
68
+ const AGENT_WATCH_DIR = ".agent-watch";
69
+ const CONFIG_FILE_NAME = "config.json";
70
+ const SESSIONS_STATE_FILE = "sessions.json";
71
+ const SUPPORTED_HOOKS = ["commit", "push"];
72
+ const SUPPORTED_AI_AGENTS = [{
73
+ value: "github-copilot-cli",
74
+ name: "GitHub Copilot CLI"
75
+ }];
76
+ const FILE_SELECTION_PAGE_SIZE = 10;
77
+
78
+ //#endregion
79
+ //#region src/config.ts
80
+ /**
81
+ * Load the agent-watch configuration from the project root.
82
+ * Returns null if no config file exists or is invalid.
83
+ */
84
+ function loadConfig(projectRoot) {
85
+ const configPath = (0, node_path.join)(projectRoot, AGENT_WATCH_DIR, CONFIG_FILE_NAME);
86
+ if (!(0, node_fs.existsSync)(configPath)) return null;
87
+ try {
88
+ const raw = (0, node_fs.readFileSync)(configPath, "utf-8");
89
+ return JSON.parse(raw);
90
+ } catch {
91
+ return null;
92
+ }
93
+ }
94
+ /**
95
+ * Save the agent-watch configuration to the project root.
96
+ */
97
+ function saveConfig(projectRoot, config) {
98
+ const agentWatchDir = (0, node_path.join)(projectRoot, AGENT_WATCH_DIR);
99
+ const configPath = (0, node_path.join)(agentWatchDir, CONFIG_FILE_NAME);
100
+ if (!(0, node_fs.existsSync)(agentWatchDir)) (0, node_fs.mkdirSync)(agentWatchDir, { recursive: true });
101
+ (0, node_fs.writeFileSync)(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
102
+ }
103
+ /**
104
+ * Create a default configuration with optional overrides.
105
+ */
106
+ function createDefaultConfig(overrides = {}) {
107
+ return {
108
+ version: 1,
109
+ agentFiles: [],
110
+ watchFileChanges: true,
111
+ includeChatSession: true,
112
+ hookTrigger: "commit",
113
+ agents: [],
114
+ ...overrides
115
+ };
116
+ }
117
+
118
+ //#endregion
119
+ //#region src/detect.ts
120
+ /**
121
+ * Scan the project root for known agent configuration files.
122
+ * Returns information about each known file pattern including whether it exists.
123
+ */
124
+ function detectAgentFiles(projectRoot) {
125
+ return KNOWN_AGENT_FILES.map((pattern) => {
126
+ const absolutePath = (0, node_path.join)(projectRoot, pattern.path);
127
+ return {
128
+ pattern,
129
+ exists: (0, node_fs.existsSync)(absolutePath),
130
+ absolutePath
131
+ };
132
+ });
133
+ }
134
+ /**
135
+ * Get only the agent files that exist in the project.
136
+ */
137
+ function getExistingAgentFiles(projectRoot) {
138
+ return detectAgentFiles(projectRoot).filter((f) => f.exists);
139
+ }
140
+
141
+ //#endregion
142
+ //#region src/utils/logger.ts
143
+ const logger = {
144
+ info(message) {
145
+ console.log(picocolors.default.blue("info"), message);
146
+ },
147
+ success(message) {
148
+ console.log(picocolors.default.green("✔"), message);
149
+ },
150
+ warn(message) {
151
+ console.log(picocolors.default.yellow("⚠"), message);
152
+ },
153
+ error(message) {
154
+ console.error(picocolors.default.red("✖"), message);
155
+ },
156
+ step(message) {
157
+ console.log(picocolors.default.cyan("▸"), message);
158
+ },
159
+ blank() {
160
+ console.log();
161
+ },
162
+ title(message) {
163
+ console.log();
164
+ console.log(picocolors.default.bold(picocolors.default.magenta(message)));
165
+ console.log();
166
+ },
167
+ banner(message) {
168
+ const border = "═".repeat(message.length + 4);
169
+ console.log();
170
+ console.log(picocolors.default.bold(picocolors.default.cyan(`╔${border}╗`)));
171
+ console.log(picocolors.default.bold(picocolors.default.cyan(`║ ${message} ║`)));
172
+ console.log(picocolors.default.bold(picocolors.default.cyan(`╚${border}╝`)));
173
+ console.log();
174
+ },
175
+ section(message) {
176
+ console.log();
177
+ console.log(picocolors.default.bold(picocolors.default.blue(`┌─ ${message}`)));
178
+ console.log(picocolors.default.bold(picocolors.default.blue("│")));
179
+ },
180
+ sectionEnd() {
181
+ console.log(picocolors.default.bold(picocolors.default.blue("└─")));
182
+ console.log();
183
+ },
184
+ asciiArt() {
185
+ console.log();
186
+ console.log(picocolors.default.bold(picocolors.default.cyan(" █████╗ ██████╗ ███████╗███╗ ██╗████████╗ ██╗ ██╗ █████╗ ████████╗ ██████╗██╗ ██╗")));
187
+ console.log(picocolors.default.bold(picocolors.default.cyan(" ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ ██║ ██║██╔══██╗╚══██╔══╝██╔════╝██║ ██║")));
188
+ console.log(picocolors.default.bold(picocolors.default.magenta(" ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ██║ █╗ ██║███████║ ██║ ██║ ███████║")));
189
+ console.log(picocolors.default.bold(picocolors.default.magenta(" ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██║███╗██║██╔══██║ ██║ ██║ ██╔══██║")));
190
+ console.log(picocolors.default.bold(picocolors.default.blue(" ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ╚███╔███╔╝██║ ██║ ██║ ╚██████╗██║ ██║")));
191
+ console.log(picocolors.default.bold(picocolors.default.blue(" ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝")));
192
+ console.log();
193
+ console.log(picocolors.default.dim(picocolors.default.italic(" Keep your AI agent configuration files in sync")));
194
+ console.log();
195
+ }
196
+ };
197
+
198
+ //#endregion
199
+ //#region src/utils/sessions.ts
200
+ const COPILOT_SESSION_STATE_DIR = (0, node_path.join)((0, node_os.homedir)(), ".copilot", "session-state");
201
+ /**
202
+ * Parse a workspace.yaml file into a CopilotSession object.
203
+ * Uses simple line-by-line parsing to avoid a YAML dependency.
204
+ */
205
+ function parseWorkspaceYaml(content) {
206
+ const result = {};
207
+ for (const line of content.split("\n")) {
208
+ const colonIndex = line.indexOf(":");
209
+ if (colonIndex === -1) continue;
210
+ const key = line.slice(0, colonIndex).trim();
211
+ result[key] = line.slice(colonIndex + 1).trim();
212
+ }
213
+ return {
214
+ id: result.id,
215
+ cwd: result.cwd,
216
+ gitRoot: result.git_root,
217
+ branch: result.branch,
218
+ createdAt: result.created_at,
219
+ updatedAt: result.updated_at
220
+ };
221
+ }
222
+ /**
223
+ * Discover Copilot CLI sessions for the given project.
224
+ * Reads workspace.yaml from each session in ~/.copilot/session-state/, filters to sessions
225
+ * matching the project's git root, and returns the latest N sessions.
226
+ */
227
+ function getCopilotSessions(projectRoot, limit = 5) {
228
+ if (!(0, node_fs.existsSync)(COPILOT_SESSION_STATE_DIR)) return [];
229
+ const sessionDirs = (0, node_fs.readdirSync)(COPILOT_SESSION_STATE_DIR, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
230
+ const sessions = [];
231
+ for (const dirName of sessionDirs) {
232
+ const workspaceFile = (0, node_path.join)(COPILOT_SESSION_STATE_DIR, dirName, "workspace.yaml");
233
+ if (!(0, node_fs.existsSync)(workspaceFile)) continue;
234
+ try {
235
+ const parsed = parseWorkspaceYaml((0, node_fs.readFileSync)(workspaceFile, "utf-8"));
236
+ if (!parsed.id || !parsed.gitRoot) continue;
237
+ if (parsed.gitRoot !== projectRoot && parsed.cwd !== projectRoot) continue;
238
+ sessions.push({
239
+ id: parsed.id,
240
+ cwd: parsed.cwd ?? projectRoot,
241
+ gitRoot: parsed.gitRoot,
242
+ branch: parsed.branch ?? "unknown",
243
+ createdAt: parsed.createdAt ?? "",
244
+ updatedAt: parsed.updatedAt ?? ""
245
+ });
246
+ } catch {}
247
+ }
248
+ sessions.sort((a, b) => {
249
+ const dateA = new Date(a.updatedAt).getTime() || 0;
250
+ return (new Date(b.updatedAt).getTime() || 0) - dateA;
251
+ });
252
+ return sessions.slice(0, limit);
253
+ }
254
+ /**
255
+ * Read the list of already-processed session IDs from the project state file.
256
+ */
257
+ function getProcessedSessionIds(projectRoot) {
258
+ const stateFile = (0, node_path.join)(projectRoot, AGENT_WATCH_DIR, SESSIONS_STATE_FILE);
259
+ if (!(0, node_fs.existsSync)(stateFile)) return [];
260
+ try {
261
+ const content = (0, node_fs.readFileSync)(stateFile, "utf-8");
262
+ const state = JSON.parse(content);
263
+ return Array.isArray(state.processedSessions) ? state.processedSessions : [];
264
+ } catch {
265
+ return [];
266
+ }
267
+ }
268
+ /**
269
+ * Save the list of processed session IDs to the project state file.
270
+ */
271
+ function saveProcessedSessionIds(projectRoot, sessionIds) {
272
+ const agentWatchDir = (0, node_path.join)(projectRoot, AGENT_WATCH_DIR);
273
+ const stateFile = (0, node_path.join)(agentWatchDir, SESSIONS_STATE_FILE);
274
+ if (!(0, node_fs.existsSync)(agentWatchDir)) (0, node_fs.mkdirSync)(agentWatchDir, { recursive: true });
275
+ (0, node_fs.writeFileSync)(stateFile, `${JSON.stringify({ processedSessions: sessionIds }, null, 2)}\n`);
276
+ }
277
+ /**
278
+ * Get sessions that haven't been processed yet.
279
+ * Returns the latest N sessions for this project, minus already-processed ones.
280
+ */
281
+ function getUnprocessedSessions(projectRoot, limit = 5) {
282
+ const sessions = getCopilotSessions(projectRoot, limit);
283
+ const processedIds = getProcessedSessionIds(projectRoot);
284
+ return sessions.filter((s) => !processedIds.includes(s.id));
285
+ }
286
+ /**
287
+ * Export session conversation content by resuming the session with Copilot CLI.
288
+ * Asks Copilot to list all user queries and agent responses from the session.
289
+ */
290
+ function exportSessionContent(sessionId) {
291
+ try {
292
+ return parseSessionOutput((0, node_child_process.execSync)(`copilot --resume ${sessionId} -p "List every user request and your response from this session. Format each pair on its own line exactly as: USER: <their message> | AGENT: <your response summary>" -s --allow-all`, {
293
+ encoding: "utf-8",
294
+ stdio: "pipe",
295
+ timeout: 12e4
296
+ }));
297
+ } catch (error) {
298
+ logger.warn(`Failed to export session ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);
299
+ return [];
300
+ }
301
+ }
302
+ /**
303
+ * Parse the copilot output into structured conversation pairs.
304
+ * Expected format per line: USER: <query> | AGENT: <response>
305
+ */
306
+ function parseSessionOutput(output) {
307
+ const conversations = [];
308
+ const lines = output.split("\n");
309
+ for (const line of lines) {
310
+ const match = /USER:\s*(.+?)\s*\|\s*AGENT:\s*(.+)/.exec(line);
311
+ if (match) conversations.push({
312
+ userQuery: match[1].trim(),
313
+ agentResponse: match[2].trim()
314
+ });
315
+ }
316
+ return conversations;
317
+ }
318
+ /**
319
+ * Process unprocessed Copilot CLI sessions for a project.
320
+ * Discovers new sessions, extracts conversation context, and marks them as processed.
321
+ * Returns the combined conversation context string for use in agent file updates.
322
+ */
323
+ function processNewSessions(projectRoot) {
324
+ const unprocessed = getUnprocessedSessions(projectRoot);
325
+ if (unprocessed.length === 0) return null;
326
+ const allConversations = [];
327
+ for (const session of unprocessed) {
328
+ const conversations = exportSessionContent(session.id);
329
+ allConversations.push(...conversations);
330
+ }
331
+ if (allConversations.length === 0) {
332
+ saveProcessedSessionIds(projectRoot, [...getProcessedSessionIds(projectRoot), ...unprocessed.map((s) => s.id)]);
333
+ return null;
334
+ }
335
+ const context = allConversations.map((c) => `User: ${c.userQuery}\nAgent: ${c.agentResponse}`).join("\n\n");
336
+ saveProcessedSessionIds(projectRoot, [...getProcessedSessionIds(projectRoot), ...unprocessed.map((s) => s.id)]);
337
+ logger.success(`Processed ${unprocessed.length} chat session(s)`);
338
+ return context;
339
+ }
340
+
341
+ //#endregion
342
+ Object.defineProperty(exports, 'AGENT_WATCH_DIR', {
343
+ enumerable: true,
344
+ get: function () {
345
+ return AGENT_WATCH_DIR;
346
+ }
347
+ });
348
+ Object.defineProperty(exports, 'CONFIG_FILE_NAME', {
349
+ enumerable: true,
350
+ get: function () {
351
+ return CONFIG_FILE_NAME;
352
+ }
353
+ });
354
+ Object.defineProperty(exports, 'FILE_SELECTION_PAGE_SIZE', {
355
+ enumerable: true,
356
+ get: function () {
357
+ return FILE_SELECTION_PAGE_SIZE;
358
+ }
359
+ });
360
+ Object.defineProperty(exports, 'KNOWN_AGENT_FILES', {
361
+ enumerable: true,
362
+ get: function () {
363
+ return KNOWN_AGENT_FILES;
364
+ }
365
+ });
366
+ Object.defineProperty(exports, 'SESSIONS_STATE_FILE', {
367
+ enumerable: true,
368
+ get: function () {
369
+ return SESSIONS_STATE_FILE;
370
+ }
371
+ });
372
+ Object.defineProperty(exports, 'SUPPORTED_AI_AGENTS', {
373
+ enumerable: true,
374
+ get: function () {
375
+ return SUPPORTED_AI_AGENTS;
376
+ }
377
+ });
378
+ Object.defineProperty(exports, 'SUPPORTED_HOOKS', {
379
+ enumerable: true,
380
+ get: function () {
381
+ return SUPPORTED_HOOKS;
382
+ }
383
+ });
384
+ Object.defineProperty(exports, '__toESM', {
385
+ enumerable: true,
386
+ get: function () {
387
+ return __toESM;
388
+ }
389
+ });
390
+ Object.defineProperty(exports, 'createDefaultConfig', {
391
+ enumerable: true,
392
+ get: function () {
393
+ return createDefaultConfig;
394
+ }
395
+ });
396
+ Object.defineProperty(exports, 'detectAgentFiles', {
397
+ enumerable: true,
398
+ get: function () {
399
+ return detectAgentFiles;
400
+ }
401
+ });
402
+ Object.defineProperty(exports, 'getCopilotSessions', {
403
+ enumerable: true,
404
+ get: function () {
405
+ return getCopilotSessions;
406
+ }
407
+ });
408
+ Object.defineProperty(exports, 'getExistingAgentFiles', {
409
+ enumerable: true,
410
+ get: function () {
411
+ return getExistingAgentFiles;
412
+ }
413
+ });
414
+ Object.defineProperty(exports, 'getUnprocessedSessions', {
415
+ enumerable: true,
416
+ get: function () {
417
+ return getUnprocessedSessions;
418
+ }
419
+ });
420
+ Object.defineProperty(exports, 'loadConfig', {
421
+ enumerable: true,
422
+ get: function () {
423
+ return loadConfig;
424
+ }
425
+ });
426
+ Object.defineProperty(exports, 'logger', {
427
+ enumerable: true,
428
+ get: function () {
429
+ return logger;
430
+ }
431
+ });
432
+ Object.defineProperty(exports, 'processNewSessions', {
433
+ enumerable: true,
434
+ get: function () {
435
+ return processNewSessions;
436
+ }
437
+ });
438
+ Object.defineProperty(exports, 'saveConfig', {
439
+ enumerable: true,
440
+ get: function () {
441
+ return saveConfig;
442
+ }
443
+ });
444
+ //# sourceMappingURL=sessions-CkCQikpl.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions-CkCQikpl.cjs","names":["pc"],"sources":["../src/constants.ts","../src/config.ts","../src/detect.ts","../src/utils/logger.ts","../src/utils/sessions.ts"],"sourcesContent":["export interface AgentFilePattern {\n\t/** Relative path from project root */\n\tpath: string\n\t/** Human-readable label for display */\n\tlabel: string\n\t/** Which AI agent/tool uses this file */\n\tagent: string\n}\n\nexport const KNOWN_AGENT_FILES: AgentFilePattern[] = [\n\t{ path: \"AGENTS.md\", label: \"AGENTS.md (Recommended)\", agent: \"Generic\" },\n\t{ path: \"CLAUDE.md\", label: \"CLAUDE.md (Claude Code)\", agent: \"Claude Code\" },\n\t{\n\t\tpath: \".github/copilot-instructions.md\",\n\t\tlabel: \".github/copilot-instructions.md (GitHub Copilot)\",\n\t\tagent: \"GitHub Copilot\",\n\t},\n\t{ path: \".cursor/rules\", label: \".cursor/rules (Cursor)\", agent: \"Cursor\" },\n\t{ path: \".windsurfrules\", label: \".windsurfrules (Windsurf)\", agent: \"Windsurf\" },\n\t{ path: \".clinerules\", label: \".clinerules (Cline)\", agent: \"Cline\" },\n]\n\n// agent-watch directory and files\nexport const AGENT_WATCH_DIR = \".agent-watch\"\nexport const CONFIG_FILE_NAME = \"config.json\"\nexport const SESSIONS_STATE_FILE = \"sessions.json\"\n\nexport const SUPPORTED_HOOKS = [\"commit\", \"push\"] as const\nexport type GitHookTrigger = (typeof SUPPORTED_HOOKS)[number]\n\nexport const SUPPORTED_AI_AGENTS = [{ value: \"github-copilot-cli\", name: \"GitHub Copilot CLI\" }] as const\n\n// UI Configuration\nexport const FILE_SELECTION_PAGE_SIZE = 10 // Static scroll limit for file selection\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { AGENT_WATCH_DIR, CONFIG_FILE_NAME, type GitHookTrigger } from \"./constants.js\"\n\nexport interface AgentWatchConfig {\n\t/** Version of the config schema */\n\tversion: 1\n\t/** Relative paths to the agent files being managed */\n\tagentFiles: string[]\n\t/** Whether to use git commit messages and chat sessions for context (legacy) */\n\tuseGitContext?: boolean\n\t/** Whether to watch for file changes */\n\twatchFileChanges: boolean\n\t/** Whether to include chat session context */\n\tincludeChatSession: boolean\n\t/** Which git hook triggers the update */\n\thookTrigger: GitHookTrigger\n\t/** Which AI agent integrations to configure */\n\tagents: string[]\n}\n\n/**\n * Load the agent-watch configuration from the project root.\n * Returns null if no config file exists or is invalid.\n */\nexport function loadConfig(projectRoot: string): AgentWatchConfig | null {\n\tconst configPath = join(projectRoot, AGENT_WATCH_DIR, CONFIG_FILE_NAME)\n\tif (!existsSync(configPath)) {\n\t\treturn null\n\t}\n\ttry {\n\t\tconst raw = readFileSync(configPath, \"utf-8\")\n\t\treturn JSON.parse(raw) as AgentWatchConfig\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Save the agent-watch configuration to the project root.\n */\nexport function saveConfig(projectRoot: string, config: AgentWatchConfig): void {\n\tconst agentWatchDir = join(projectRoot, AGENT_WATCH_DIR)\n\tconst configPath = join(agentWatchDir, CONFIG_FILE_NAME)\n\n\t// Ensure directory exists\n\tif (!existsSync(agentWatchDir)) {\n\t\tmkdirSync(agentWatchDir, { recursive: true })\n\t}\n\n\twriteFileSync(configPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\")\n}\n\n/**\n * Create a default configuration with optional overrides.\n */\nexport function createDefaultConfig(overrides: Partial<AgentWatchConfig> = {}): AgentWatchConfig {\n\treturn {\n\t\tversion: 1,\n\t\tagentFiles: [],\n\t\twatchFileChanges: true,\n\t\tincludeChatSession: true,\n\t\thookTrigger: \"commit\",\n\t\tagents: [],\n\t\t...overrides,\n\t}\n}\n","import { existsSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { type AgentFilePattern, KNOWN_AGENT_FILES } from \"./constants.js\"\n\nexport interface AgentFileInfo {\n\tpattern: AgentFilePattern\n\texists: boolean\n\tabsolutePath: string\n}\n\n/**\n * Scan the project root for known agent configuration files.\n * Returns information about each known file pattern including whether it exists.\n */\nexport function detectAgentFiles(projectRoot: string): AgentFileInfo[] {\n\treturn KNOWN_AGENT_FILES.map((pattern) => {\n\t\tconst absolutePath = join(projectRoot, pattern.path)\n\t\treturn {\n\t\t\tpattern,\n\t\t\texists: existsSync(absolutePath),\n\t\t\tabsolutePath,\n\t\t}\n\t})\n}\n\n/**\n * Get only the agent files that exist in the project.\n */\nexport function getExistingAgentFiles(projectRoot: string): AgentFileInfo[] {\n\treturn detectAgentFiles(projectRoot).filter((f) => f.exists)\n}\n","import pc from \"picocolors\"\n\nexport const logger = {\n\tinfo(message: string): void {\n\t\tconsole.log(pc.blue(\"info\"), message)\n\t},\n\n\tsuccess(message: string): void {\n\t\tconsole.log(pc.green(\"✔\"), message)\n\t},\n\n\twarn(message: string): void {\n\t\tconsole.log(pc.yellow(\"⚠\"), message)\n\t},\n\n\terror(message: string): void {\n\t\tconsole.error(pc.red(\"✖\"), message)\n\t},\n\n\tstep(message: string): void {\n\t\tconsole.log(pc.cyan(\"▸\"), message)\n\t},\n\n\tblank(): void {\n\t\tconsole.log()\n\t},\n\n\ttitle(message: string): void {\n\t\tconsole.log()\n\t\tconsole.log(pc.bold(pc.magenta(message)))\n\t\tconsole.log()\n\t},\n\n\tbanner(message: string): void {\n\t\tconst border = \"═\".repeat(message.length + 4)\n\t\tconsole.log()\n\t\tconsole.log(pc.bold(pc.cyan(`╔${border}╗`)))\n\t\tconsole.log(pc.bold(pc.cyan(`║ ${message} ║`)))\n\t\tconsole.log(pc.bold(pc.cyan(`╚${border}╝`)))\n\t\tconsole.log()\n\t},\n\n\tsection(message: string): void {\n\t\tconsole.log()\n\t\tconsole.log(pc.bold(pc.blue(`┌─ ${message}`)))\n\t\tconsole.log(pc.bold(pc.blue(\"│\")))\n\t},\n\n\tsectionEnd(): void {\n\t\tconsole.log(pc.bold(pc.blue(\"└─\")))\n\t\tconsole.log()\n\t},\n\n\tasciiArt(): void {\n\t\tconsole.log()\n\t\tconsole.log(\n\t\t\tpc.bold(pc.cyan(\" █████╗ ██████╗ ███████╗███╗ ██╗████████╗ ██╗ ██╗ █████╗ ████████╗ ██████╗██╗ ██╗\"))\n\t\t)\n\t\tconsole.log(\n\t\t\tpc.bold(pc.cyan(\" ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ ██║ ██║██╔══██╗╚══██╔══╝██╔════╝██║ ██║\"))\n\t\t)\n\t\tconsole.log(\n\t\t\tpc.bold(\n\t\t\t\tpc.magenta(\" ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ██║ █╗ ██║███████║ ██║ ██║ ███████║\")\n\t\t\t)\n\t\t)\n\t\tconsole.log(\n\t\t\tpc.bold(\n\t\t\t\tpc.magenta(\" ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██║███╗██║██╔══██║ ██║ ██║ ██╔══██║\")\n\t\t\t)\n\t\t)\n\t\tconsole.log(\n\t\t\tpc.bold(pc.blue(\" ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ╚███╔███╔╝██║ ██║ ██║ ╚██████╗██║ ██║\"))\n\t\t)\n\t\tconsole.log(\n\t\t\tpc.bold(pc.blue(\" ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝\"))\n\t\t)\n\t\tconsole.log()\n\t\tconsole.log(pc.dim(pc.italic(\" Keep your AI agent configuration files in sync\")))\n\t\tconsole.log()\n\t},\n}\n","import { execSync } from \"node:child_process\"\nimport { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { join } from \"node:path\"\nimport { AGENT_WATCH_DIR, SESSIONS_STATE_FILE } from \"../constants.js\"\nimport { logger } from \"./logger.js\"\n\nexport interface CopilotSession {\n\tid: string\n\tcwd: string\n\tgitRoot: string\n\tbranch: string\n\tcreatedAt: string\n\tupdatedAt: string\n}\n\nexport interface SessionConversation {\n\tuserQuery: string\n\tagentResponse: string\n}\n\nconst COPILOT_SESSION_STATE_DIR = join(homedir(), \".copilot\", \"session-state\")\n\n/**\n * Parse a workspace.yaml file into a CopilotSession object.\n * Uses simple line-by-line parsing to avoid a YAML dependency.\n */\nfunction parseWorkspaceYaml(content: string): Partial<CopilotSession> {\n\tconst result: Record<string, string> = {}\n\tfor (const line of content.split(\"\\n\")) {\n\t\tconst colonIndex = line.indexOf(\":\")\n\t\tif (colonIndex === -1) continue\n\t\tconst key = line.slice(0, colonIndex).trim()\n\t\tconst value = line.slice(colonIndex + 1).trim()\n\t\tresult[key] = value\n\t}\n\treturn {\n\t\tid: result.id,\n\t\tcwd: result.cwd,\n\t\tgitRoot: result.git_root,\n\t\tbranch: result.branch,\n\t\tcreatedAt: result.created_at,\n\t\tupdatedAt: result.updated_at,\n\t}\n}\n\n/**\n * Discover Copilot CLI sessions for the given project.\n * Reads workspace.yaml from each session in ~/.copilot/session-state/, filters to sessions\n * matching the project's git root, and returns the latest N sessions.\n */\nexport function getCopilotSessions(projectRoot: string, limit = 5): CopilotSession[] {\n\tif (!existsSync(COPILOT_SESSION_STATE_DIR)) {\n\t\treturn []\n\t}\n\n\tconst sessionDirs = readdirSync(COPILOT_SESSION_STATE_DIR, { withFileTypes: true })\n\t\t.filter((d) => d.isDirectory())\n\t\t.map((d) => d.name)\n\n\tconst sessions: CopilotSession[] = []\n\n\tfor (const dirName of sessionDirs) {\n\t\tconst workspaceFile = join(COPILOT_SESSION_STATE_DIR, dirName, \"workspace.yaml\")\n\t\tif (!existsSync(workspaceFile)) continue\n\n\t\ttry {\n\t\t\tconst content = readFileSync(workspaceFile, \"utf-8\")\n\t\t\tconst parsed = parseWorkspaceYaml(content)\n\n\t\t\tif (!parsed.id || !parsed.gitRoot) continue\n\n\t\t\t// Filter to sessions belonging to this project\n\t\t\tif (parsed.gitRoot !== projectRoot && parsed.cwd !== projectRoot) continue\n\n\t\t\tsessions.push({\n\t\t\t\tid: parsed.id,\n\t\t\t\tcwd: parsed.cwd ?? projectRoot,\n\t\t\t\tgitRoot: parsed.gitRoot,\n\t\t\t\tbranch: parsed.branch ?? \"unknown\",\n\t\t\t\tcreatedAt: parsed.createdAt ?? \"\",\n\t\t\t\tupdatedAt: parsed.updatedAt ?? \"\",\n\t\t\t})\n\t\t} catch {\n\t\t\t// Skip malformed session files\n\t\t}\n\t}\n\n\t// Sort by updatedAt descending (most recent first)\n\tsessions.sort((a, b) => {\n\t\tconst dateA = new Date(a.updatedAt).getTime() || 0\n\t\tconst dateB = new Date(b.updatedAt).getTime() || 0\n\t\treturn dateB - dateA\n\t})\n\n\treturn sessions.slice(0, limit)\n}\n\n/**\n * Read the list of already-processed session IDs from the project state file.\n */\nexport function getProcessedSessionIds(projectRoot: string): string[] {\n\tconst stateFile = join(projectRoot, AGENT_WATCH_DIR, SESSIONS_STATE_FILE)\n\tif (!existsSync(stateFile)) return []\n\n\ttry {\n\t\tconst content = readFileSync(stateFile, \"utf-8\")\n\t\tconst state = JSON.parse(content)\n\t\treturn Array.isArray(state.processedSessions) ? state.processedSessions : []\n\t} catch {\n\t\treturn []\n\t}\n}\n\n/**\n * Save the list of processed session IDs to the project state file.\n */\nexport function saveProcessedSessionIds(projectRoot: string, sessionIds: string[]): void {\n\tconst agentWatchDir = join(projectRoot, AGENT_WATCH_DIR)\n\tconst stateFile = join(agentWatchDir, SESSIONS_STATE_FILE)\n\n\t// Ensure directory exists\n\tif (!existsSync(agentWatchDir)) {\n\t\tmkdirSync(agentWatchDir, { recursive: true })\n\t}\n\n\tconst content = JSON.stringify({ processedSessions: sessionIds }, null, 2)\n\twriteFileSync(stateFile, `${content}\\n`)\n}\n\n/**\n * Get sessions that haven't been processed yet.\n * Returns the latest N sessions for this project, minus already-processed ones.\n */\nexport function getUnprocessedSessions(projectRoot: string, limit = 5): CopilotSession[] {\n\tconst sessions = getCopilotSessions(projectRoot, limit)\n\tconst processedIds = getProcessedSessionIds(projectRoot)\n\treturn sessions.filter((s) => !processedIds.includes(s.id))\n}\n\n/**\n * Export session conversation content by resuming the session with Copilot CLI.\n * Asks Copilot to list all user queries and agent responses from the session.\n */\nexport function exportSessionContent(sessionId: string): SessionConversation[] {\n\ttry {\n\t\tconst output = execSync(\n\t\t\t`copilot --resume ${sessionId} -p \"List every user request and your response from this session. Format each pair on its own line exactly as: USER: <their message> | AGENT: <your response summary>\" -s --allow-all`,\n\t\t\t{\n\t\t\t\tencoding: \"utf-8\",\n\t\t\t\tstdio: \"pipe\",\n\t\t\t\ttimeout: 120_000,\n\t\t\t}\n\t\t)\n\t\treturn parseSessionOutput(output)\n\t} catch (error) {\n\t\tlogger.warn(`Failed to export session ${sessionId}: ${error instanceof Error ? error.message : String(error)}`)\n\t\treturn []\n\t}\n}\n\n/**\n * Parse the copilot output into structured conversation pairs.\n * Expected format per line: USER: <query> | AGENT: <response>\n */\nexport function parseSessionOutput(output: string): SessionConversation[] {\n\tconst conversations: SessionConversation[] = []\n\tconst lines = output.split(\"\\n\")\n\n\tfor (const line of lines) {\n\t\tconst match = /USER:\\s*(.+?)\\s*\\|\\s*AGENT:\\s*(.+)/.exec(line)\n\t\tif (match) {\n\t\t\tconversations.push({\n\t\t\t\tuserQuery: match[1].trim(),\n\t\t\t\tagentResponse: match[2].trim(),\n\t\t\t})\n\t\t}\n\t}\n\n\treturn conversations\n}\n\n/**\n * Process unprocessed Copilot CLI sessions for a project.\n * Discovers new sessions, extracts conversation context, and marks them as processed.\n * Returns the combined conversation context string for use in agent file updates.\n */\nexport function processNewSessions(projectRoot: string): string | null {\n\tconst unprocessed = getUnprocessedSessions(projectRoot)\n\n\tif (unprocessed.length === 0) {\n\t\treturn null\n\t}\n\n\tconst allConversations: SessionConversation[] = []\n\n\tfor (const session of unprocessed) {\n\t\tconst conversations = exportSessionContent(session.id)\n\t\tallConversations.push(...conversations)\n\t}\n\n\tif (allConversations.length === 0) {\n\t\t// Still mark as processed to avoid re-checking empty sessions\n\t\tconst processedIds = getProcessedSessionIds(projectRoot)\n\t\tsaveProcessedSessionIds(projectRoot, [...processedIds, ...unprocessed.map((s) => s.id)])\n\t\treturn null\n\t}\n\n\t// Format conversations as context\n\tconst context = allConversations.map((c) => `User: ${c.userQuery}\\nAgent: ${c.agentResponse}`).join(\"\\n\\n\")\n\n\t// Mark sessions as processed\n\tconst processedIds = getProcessedSessionIds(projectRoot)\n\tsaveProcessedSessionIds(projectRoot, [...processedIds, ...unprocessed.map((s) => s.id)])\n\n\tlogger.success(`Processed ${unprocessed.length} chat session(s)`)\n\n\treturn context\n}\n"],"mappings":"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"}