agentpilot 0.1.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 (47) hide show
  1. package/README.md +121 -0
  2. package/dist/commands/init.d.ts +10 -0
  3. package/dist/commands/init.js +262 -0
  4. package/dist/commands/init.js.map +1 -0
  5. package/dist/commands/login.d.ts +4 -0
  6. package/dist/commands/login.js +34 -0
  7. package/dist/commands/login.js.map +1 -0
  8. package/dist/commands/status.d.ts +4 -0
  9. package/dist/commands/status.js +72 -0
  10. package/dist/commands/status.js.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +115 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/lib/api.d.ts +22 -0
  15. package/dist/lib/api.js +50 -0
  16. package/dist/lib/api.js.map +1 -0
  17. package/dist/lib/config.d.ts +4 -0
  18. package/dist/lib/config.js +28 -0
  19. package/dist/lib/config.js.map +1 -0
  20. package/dist/lib/detect.d.ts +9 -0
  21. package/dist/lib/detect.js +25 -0
  22. package/dist/lib/detect.js.map +1 -0
  23. package/dist/lib/fs-utils.d.ts +23 -0
  24. package/dist/lib/fs-utils.js +120 -0
  25. package/dist/lib/fs-utils.js.map +1 -0
  26. package/dist/lib/merge-claude.d.ts +17 -0
  27. package/dist/lib/merge-claude.js +143 -0
  28. package/dist/lib/merge-claude.js.map +1 -0
  29. package/dist/lib/merge-cursor.d.ts +5 -0
  30. package/dist/lib/merge-cursor.js +89 -0
  31. package/dist/lib/merge-cursor.js.map +1 -0
  32. package/dist/lib/merge-windsurf.d.ts +5 -0
  33. package/dist/lib/merge-windsurf.js +85 -0
  34. package/dist/lib/merge-windsurf.js.map +1 -0
  35. package/dist/lib/prompts.d.ts +19 -0
  36. package/dist/lib/prompts.js +62 -0
  37. package/dist/lib/prompts.js.map +1 -0
  38. package/dist/lib/templates.d.ts +5 -0
  39. package/dist/lib/templates.js +157 -0
  40. package/dist/lib/templates.js.map +1 -0
  41. package/dist/lib/verify.d.ts +5 -0
  42. package/dist/lib/verify.js +37 -0
  43. package/dist/lib/verify.js.map +1 -0
  44. package/dist/types.d.ts +33 -0
  45. package/dist/types.js +11 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +42 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { ListAgentsResponse, CreateAgentResponse, AgentResponse, AgentType } from "../types.js";
2
+ export declare class ApiError extends Error {
3
+ status: number;
4
+ body?: Record<string, unknown> | undefined;
5
+ constructor(message: string, status: number, body?: Record<string, unknown> | undefined);
6
+ }
7
+ export declare function listAgents(apiKey: string, baseUrl?: string): Promise<ListAgentsResponse>;
8
+ export declare function getAgent(apiKey: string, agentId: string, baseUrl?: string): Promise<{
9
+ agent: AgentResponse;
10
+ }>;
11
+ export declare function createAgent(apiKey: string, data: {
12
+ name: string;
13
+ type: AgentType;
14
+ icon?: string;
15
+ }, baseUrl?: string): Promise<CreateAgentResponse>;
16
+ export declare function sendEvent(apiKey: string, data: {
17
+ agentId: string;
18
+ event: string;
19
+ summary: string;
20
+ cost: number;
21
+ metadata?: Record<string, unknown>;
22
+ }, baseUrl?: string): Promise<unknown>;
@@ -0,0 +1,50 @@
1
+ const DEFAULT_BASE_URL = "https://app.agentpilot.dev";
2
+ function getBaseUrl() {
3
+ return process.env.AGENTPILOT_BASE_URL || DEFAULT_BASE_URL;
4
+ }
5
+ export class ApiError extends Error {
6
+ status;
7
+ body;
8
+ constructor(message, status, body) {
9
+ super(message);
10
+ this.status = status;
11
+ this.body = body;
12
+ this.name = "ApiError";
13
+ }
14
+ }
15
+ async function request(path, apiKey, options = {}, baseUrl) {
16
+ const url = `${baseUrl || getBaseUrl()}${path}`;
17
+ const res = await fetch(url, {
18
+ ...options,
19
+ headers: {
20
+ Authorization: `Bearer ${apiKey}`,
21
+ "Content-Type": "application/json",
22
+ ...options.headers,
23
+ },
24
+ signal: AbortSignal.timeout(15000),
25
+ });
26
+ const body = (await res.json());
27
+ if (!res.ok) {
28
+ throw new ApiError(body.error || `HTTP ${res.status}`, res.status, body);
29
+ }
30
+ return body;
31
+ }
32
+ export async function listAgents(apiKey, baseUrl) {
33
+ return request("/api/v1/agents", apiKey, {}, baseUrl);
34
+ }
35
+ export async function getAgent(apiKey, agentId, baseUrl) {
36
+ return request(`/api/v1/agents/${agentId}`, apiKey, {}, baseUrl);
37
+ }
38
+ export async function createAgent(apiKey, data, baseUrl) {
39
+ return request("/api/v1/agents", apiKey, {
40
+ method: "POST",
41
+ body: JSON.stringify(data),
42
+ }, baseUrl);
43
+ }
44
+ export async function sendEvent(apiKey, data, baseUrl) {
45
+ return request("/api/v1/events", apiKey, {
46
+ method: "POST",
47
+ body: JSON.stringify(data),
48
+ }, baseUrl);
49
+ }
50
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAOA,MAAM,gBAAgB,GAAG,4BAA4B,CAAC;AAEtD,SAAS,UAAU;IACjB,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,gBAAgB,CAAC;AAC7D,CAAC;AAED,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGxB;IACA;IAHT,YACE,OAAe,EACR,MAAc,EACd,IAA8B;QAErC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAA0B;QAGrC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,KAAK,UAAU,OAAO,CACpB,IAAY,EACZ,MAAc,EACd,UAAuB,EAAE,EACzB,OAAgB;IAEhB,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,UAAU,EAAE,GAAG,IAAI,EAAE,CAAC;IAChD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,GAAG,OAAO;QACV,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,MAAM,EAAE;YACjC,cAAc,EAAE,kBAAkB;YAClC,GAAG,OAAO,CAAC,OAAO;SACnB;QACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;KACnC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA2B,CAAC;IAE1D,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,QAAQ,CAChB,IAAI,CAAC,KAAK,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,EAClC,GAAG,CAAC,MAAM,EACV,IAA+B,CAChC,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAc,EACd,OAAgB;IAEhB,OAAO,OAAO,CAAqB,gBAAgB,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAc,EACd,OAAe,EACf,OAAgB;IAEhB,OAAO,OAAO,CACZ,kBAAkB,OAAO,EAAE,EAC3B,MAAM,EACN,EAAE,EACF,OAAO,CACR,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,IAAsD,EACtD,OAAgB;IAEhB,OAAO,OAAO,CACZ,gBAAgB,EAChB,MAAM,EACN;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,EACD,OAAO,CACR,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,MAAc,EACd,IAMC,EACD,OAAgB;IAEhB,OAAO,OAAO,CACZ,gBAAgB,EAChB,MAAM,EACN;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,EACD,OAAO,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { CliConfig } from "../types.js";
2
+ export declare function readConfig(): Promise<CliConfig | null>;
3
+ export declare function writeConfig(config: CliConfig): Promise<void>;
4
+ export declare function getConfigPath(): string;
@@ -0,0 +1,28 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import os from "os";
4
+ const CONFIG_DIR = path.join(os.homedir(), ".agentpilot");
5
+ const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
6
+ export async function readConfig() {
7
+ try {
8
+ const raw = await fs.readFile(CONFIG_FILE, "utf8");
9
+ return JSON.parse(raw);
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ export async function writeConfig(config) {
16
+ if (process.platform !== "win32") {
17
+ await fs.mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
18
+ }
19
+ else {
20
+ await fs.mkdir(CONFIG_DIR, { recursive: true });
21
+ }
22
+ const content = JSON.stringify(config, null, 2) + "\n";
23
+ await fs.writeFile(CONFIG_FILE, content, { encoding: "utf8", mode: 0o600 });
24
+ }
25
+ export function getConfigPath() {
26
+ return CONFIG_FILE;
27
+ }
28
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAGpB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;AAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAiB;IACjD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;IACvD,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { CliSupportedType } from "../types.js";
2
+ interface DetectedIde {
3
+ type: CliSupportedType;
4
+ label: string;
5
+ }
6
+ export declare function detectIdes(cwd: string): DetectedIde[];
7
+ export declare function isVscodeCopilotProject(cwd: string): boolean;
8
+ export declare function getIdeLabel(type: CliSupportedType): string;
9
+ export {};
@@ -0,0 +1,25 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ const IDE_MARKERS = [
4
+ { dir: ".claude", type: "claude-code", label: "Claude Code" },
5
+ { dir: ".cursor", type: "cursor", label: "Cursor" },
6
+ { dir: ".windsurf", type: "windsurf", label: "Windsurf" },
7
+ ];
8
+ const VSCODE_COPILOT_MARKERS = [".agent.md"];
9
+ export function detectIdes(cwd) {
10
+ const detected = [];
11
+ for (const marker of IDE_MARKERS) {
12
+ if (fs.existsSync(path.join(cwd, marker.dir))) {
13
+ detected.push({ type: marker.type, label: marker.label });
14
+ }
15
+ }
16
+ return detected;
17
+ }
18
+ export function isVscodeCopilotProject(cwd) {
19
+ return VSCODE_COPILOT_MARKERS.some((m) => fs.existsSync(path.join(cwd, m)));
20
+ }
21
+ export function getIdeLabel(type) {
22
+ const marker = IDE_MARKERS.find((m) => m.type === type);
23
+ return marker?.label ?? type;
24
+ }
25
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/lib/detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAQxB,MAAM,WAAW,GAA6D;IAC5E,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;IAC7D,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IACnD,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;CAC1D,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,WAAW,CAAC,CAAC;AAE7C,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,QAAQ,GAAkB,EAAE,CAAC;IAEnC,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;QACjC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACvC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CACjC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAsB;IAChD,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACxD,OAAO,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Write file with LF line endings, creating parent directories as needed.
3
+ */
4
+ export declare function writeFileLF(filePath: string, content: string): Promise<void>;
5
+ /**
6
+ * chmod on Unix, no-op on Windows.
7
+ */
8
+ export declare function chmodUnix(filePath: string, mode: number): Promise<void>;
9
+ /**
10
+ * Create a timestamped backup of a file. Returns the backup path, or null if
11
+ * the source file doesn't exist.
12
+ */
13
+ export declare function backupFile(filePath: string): Promise<string | null>;
14
+ /**
15
+ * Prune old backup files, keeping only the most recent `keep` backups.
16
+ */
17
+ export declare function pruneBackups(filePath: string, keep?: number): Promise<void>;
18
+ /**
19
+ * Compute a unified-style diff between two strings (for display).
20
+ * Normalizes line endings before comparing so CRLF vs LF doesn't cause
21
+ * every line to show as changed. Returns null if strings are identical.
22
+ */
23
+ export declare function simpleDiff(oldContent: string, newContent: string, label: string): string | null;
@@ -0,0 +1,120 @@
1
+ import fs from "fs/promises";
2
+ import fss from "fs";
3
+ import path from "path";
4
+ /**
5
+ * Write file with LF line endings, creating parent directories as needed.
6
+ */
7
+ export async function writeFileLF(filePath, content) {
8
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
9
+ // Ensure LF-only line endings
10
+ const lfContent = content.replace(/\r\n/g, "\n");
11
+ await fs.writeFile(filePath, lfContent, { encoding: "utf8" });
12
+ }
13
+ /**
14
+ * chmod on Unix, no-op on Windows.
15
+ */
16
+ export async function chmodUnix(filePath, mode) {
17
+ if (process.platform !== "win32") {
18
+ await fs.chmod(filePath, mode);
19
+ }
20
+ }
21
+ /**
22
+ * Create a timestamped backup of a file. Returns the backup path, or null if
23
+ * the source file doesn't exist.
24
+ */
25
+ export async function backupFile(filePath) {
26
+ if (!fss.existsSync(filePath))
27
+ return null;
28
+ const timestamp = Math.floor(Date.now() / 1000);
29
+ const backupPath = `${filePath}.bak.${timestamp}`;
30
+ await fs.copyFile(filePath, backupPath);
31
+ return backupPath;
32
+ }
33
+ /**
34
+ * Prune old backup files, keeping only the most recent `keep` backups.
35
+ */
36
+ export async function pruneBackups(filePath, keep = 3) {
37
+ const dir = path.dirname(filePath);
38
+ const baseName = path.basename(filePath);
39
+ const pattern = `${baseName}.bak.`;
40
+ let entries;
41
+ try {
42
+ entries = await fs.readdir(dir);
43
+ }
44
+ catch {
45
+ return;
46
+ }
47
+ const backups = entries
48
+ .filter((e) => e.startsWith(pattern))
49
+ .sort()
50
+ .reverse();
51
+ for (const backup of backups.slice(keep)) {
52
+ try {
53
+ await fs.unlink(path.join(dir, backup));
54
+ }
55
+ catch {
56
+ // ignore
57
+ }
58
+ }
59
+ }
60
+ /**
61
+ * Compute a unified-style diff between two strings (for display).
62
+ * Normalizes line endings before comparing so CRLF vs LF doesn't cause
63
+ * every line to show as changed. Returns null if strings are identical.
64
+ */
65
+ export function simpleDiff(oldContent, newContent, label) {
66
+ // Normalize CRLF → LF before comparing
67
+ const normOld = oldContent.replace(/\r\n/g, "\n");
68
+ const normNew = newContent.replace(/\r\n/g, "\n");
69
+ if (normOld === normNew)
70
+ return null;
71
+ const oldLines = normOld.split("\n");
72
+ const newLines = normNew.split("\n");
73
+ // Find changed line indices
74
+ const maxLen = Math.max(oldLines.length, newLines.length);
75
+ const changedIndices = [];
76
+ for (let i = 0; i < maxLen; i++) {
77
+ if (oldLines[i] !== newLines[i]) {
78
+ changedIndices.push(i);
79
+ }
80
+ }
81
+ if (changedIndices.length === 0)
82
+ return null;
83
+ // Build unified diff with context (2 lines around each change)
84
+ const CONTEXT = 2;
85
+ const output = [`--- ${label}`, `+++ ${label} (proposed)`];
86
+ // Group consecutive changed regions
87
+ let regionStart = changedIndices[0];
88
+ let regionEnd = changedIndices[0];
89
+ const flushRegion = (start, end) => {
90
+ const ctxStart = Math.max(0, start - CONTEXT);
91
+ const ctxEnd = Math.min(maxLen - 1, end + CONTEXT);
92
+ output.push(`@@ line ${ctxStart + 1} @@`);
93
+ for (let i = ctxStart; i <= ctxEnd; i++) {
94
+ const isChanged = i >= start && i <= end && oldLines[i] !== newLines[i];
95
+ if (isChanged) {
96
+ if (oldLines[i] !== undefined)
97
+ output.push(`- ${oldLines[i]}`);
98
+ if (newLines[i] !== undefined)
99
+ output.push(`+ ${newLines[i]}`);
100
+ }
101
+ else {
102
+ output.push(` ${oldLines[i] ?? newLines[i]}`);
103
+ }
104
+ }
105
+ };
106
+ for (let k = 1; k < changedIndices.length; k++) {
107
+ if (changedIndices[k] - regionEnd <= CONTEXT * 2 + 1) {
108
+ // Merge with current region
109
+ regionEnd = changedIndices[k];
110
+ }
111
+ else {
112
+ flushRegion(regionStart, regionEnd);
113
+ regionStart = changedIndices[k];
114
+ regionEnd = changedIndices[k];
115
+ }
116
+ }
117
+ flushRegion(regionStart, regionEnd);
118
+ return output.join("\n");
119
+ }
120
+ //# sourceMappingURL=fs-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-utils.js","sourceRoot":"","sources":["../../src/lib/fs-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Merge AgentPilot hooks into .claude/settings.json.
3
+ * Returns { changed, backupPath, settingsPath }.
4
+ */
5
+ export declare function mergeClaude(projectDir: string, webhookUrl: string): Promise<{
6
+ changed: boolean;
7
+ backupPath: string | null;
8
+ settingsPath: string;
9
+ }>;
10
+ /**
11
+ * Preview what merge would produce (for diff display).
12
+ */
13
+ export declare function previewClaude(projectDir: string): Promise<{
14
+ current: string;
15
+ proposed: string;
16
+ settingsPath: string;
17
+ }>;
@@ -0,0 +1,143 @@
1
+ import fs from "fs/promises";
2
+ import fss from "fs";
3
+ import path from "path";
4
+ import { backupFile, pruneBackups, writeFileLF, chmodUnix } from "./fs-utils.js";
5
+ import { buildClaudeCodeFiles } from "./templates.js";
6
+ const AGENTPILOT_MARKER = "agentpilot-";
7
+ function isAgentpilotEntry(entry) {
8
+ return entry.hooks?.some((h) => h.command?.includes(AGENTPILOT_MARKER)) ?? false;
9
+ }
10
+ function getExpectedEntries() {
11
+ return {
12
+ PostToolUse: {
13
+ matcher: "Bash",
14
+ hooks: [
15
+ {
16
+ type: "command",
17
+ command: "bash .claude/hooks/agentpilot-report.sh",
18
+ },
19
+ ],
20
+ },
21
+ Stop: {
22
+ matcher: "",
23
+ hooks: [
24
+ {
25
+ type: "command",
26
+ command: "bash .claude/hooks/agentpilot-session.sh",
27
+ },
28
+ ],
29
+ },
30
+ };
31
+ }
32
+ /**
33
+ * Merge AgentPilot hooks into .claude/settings.json.
34
+ * Returns { changed, backupPath, settingsPath }.
35
+ */
36
+ export async function mergeClaude(projectDir, webhookUrl) {
37
+ const settingsPath = path.join(projectDir, ".claude", "settings.json");
38
+ const expectedEntries = getExpectedEntries();
39
+ // Read existing settings
40
+ let settings = {};
41
+ if (fss.existsSync(settingsPath)) {
42
+ const raw = await fs.readFile(settingsPath, "utf8");
43
+ try {
44
+ settings = JSON.parse(raw);
45
+ }
46
+ catch {
47
+ throw new Error(`Failed to parse ${settingsPath} — file is not valid JSON. Fix it manually before running init.`);
48
+ }
49
+ }
50
+ // Validate hooks shape
51
+ if (settings.hooks !== undefined && (typeof settings.hooks !== "object" || Array.isArray(settings.hooks))) {
52
+ throw new Error(`${settingsPath} has invalid "hooks" field (expected object). Fix it manually before running init.`);
53
+ }
54
+ if (!settings.hooks) {
55
+ settings.hooks = {};
56
+ }
57
+ let changed = false;
58
+ for (const [eventType, newEntry] of Object.entries(expectedEntries)) {
59
+ const arr = settings.hooks[eventType];
60
+ if (!arr) {
61
+ settings.hooks[eventType] = [newEntry];
62
+ changed = true;
63
+ }
64
+ else if (Array.isArray(arr)) {
65
+ const apEntries = arr.filter(isAgentpilotEntry);
66
+ if (apEntries.length === 0) {
67
+ arr.push(newEntry);
68
+ changed = true;
69
+ }
70
+ else if (apEntries.length === 1) {
71
+ const idx = arr.indexOf(apEntries[0]);
72
+ if (JSON.stringify(arr[idx]) !== JSON.stringify(newEntry)) {
73
+ arr[idx] = newEntry;
74
+ changed = true;
75
+ }
76
+ }
77
+ else {
78
+ // Multiple AP entries: remove extras, replace first
79
+ const firstIdx = arr.indexOf(apEntries[0]);
80
+ for (let i = apEntries.length - 1; i >= 1; i--) {
81
+ arr.splice(arr.indexOf(apEntries[i]), 1);
82
+ }
83
+ arr[firstIdx] = newEntry;
84
+ changed = true;
85
+ }
86
+ }
87
+ }
88
+ // Backup and write
89
+ let backupPath = null;
90
+ if (changed) {
91
+ backupPath = await backupFile(settingsPath);
92
+ const content = JSON.stringify(settings, null, 2) + "\n";
93
+ await writeFileLF(settingsPath, content);
94
+ await pruneBackups(settingsPath);
95
+ }
96
+ // Write hook scripts
97
+ const hookFiles = buildClaudeCodeFiles(webhookUrl);
98
+ for (const file of hookFiles) {
99
+ const filePath = path.join(projectDir, file.name);
100
+ await writeFileLF(filePath, file.content);
101
+ if (file.name.endsWith(".sh")) {
102
+ await chmodUnix(filePath, 0o755);
103
+ }
104
+ }
105
+ return { changed, backupPath, settingsPath };
106
+ }
107
+ /**
108
+ * Preview what merge would produce (for diff display).
109
+ */
110
+ export async function previewClaude(projectDir) {
111
+ const settingsPath = path.join(projectDir, ".claude", "settings.json");
112
+ let current = "{}";
113
+ if (fss.existsSync(settingsPath)) {
114
+ current = await fs.readFile(settingsPath, "utf8");
115
+ }
116
+ const settings = JSON.parse(current);
117
+ const expectedEntries = getExpectedEntries();
118
+ if (!settings.hooks) {
119
+ settings.hooks = {};
120
+ }
121
+ for (const [eventType, newEntry] of Object.entries(expectedEntries)) {
122
+ const arr = settings.hooks[eventType];
123
+ if (!arr) {
124
+ settings.hooks[eventType] = [newEntry];
125
+ }
126
+ else if (Array.isArray(arr)) {
127
+ const apEntries = arr.filter(isAgentpilotEntry);
128
+ if (apEntries.length === 0) {
129
+ arr.push(newEntry);
130
+ }
131
+ else {
132
+ const firstIdx = arr.indexOf(apEntries[0]);
133
+ for (let i = apEntries.length - 1; i >= 1; i--) {
134
+ arr.splice(arr.indexOf(apEntries[i]), 1);
135
+ }
136
+ arr[firstIdx] = newEntry;
137
+ }
138
+ }
139
+ }
140
+ const proposed = JSON.stringify(settings, null, 2) + "\n";
141
+ return { current, proposed, settingsPath };
142
+ }
143
+ //# sourceMappingURL=merge-claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-claude.js","sourceRoot":"","sources":["../../src/lib/merge-claude.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function mergeCursor(projectDir: string, webhookUrl: string): Promise<{
2
+ changed: boolean;
3
+ backupPath: string | null;
4
+ hooksPath: string;
5
+ }>;
@@ -0,0 +1,89 @@
1
+ import fs from "fs/promises";
2
+ import fss from "fs";
3
+ import path from "path";
4
+ import { backupFile, pruneBackups, writeFileLF, chmodUnix } from "./fs-utils.js";
5
+ import { buildCursorFiles } from "./templates.js";
6
+ const AGENTPILOT_MARKER = "agentpilot-";
7
+ function isAgentpilotEntry(entry) {
8
+ return entry.command?.includes(AGENTPILOT_MARKER) ?? false;
9
+ }
10
+ function getExpectedEntries() {
11
+ return {
12
+ afterFileEdit: {
13
+ command: "bash .cursor/hooks/agentpilot-report.sh",
14
+ events: ["afterFileEdit"],
15
+ },
16
+ stop: {
17
+ command: "bash .cursor/hooks/agentpilot-session.sh",
18
+ events: ["stop"],
19
+ },
20
+ };
21
+ }
22
+ export async function mergeCursor(projectDir, webhookUrl) {
23
+ const hooksPath = path.join(projectDir, ".cursor", "hooks.json");
24
+ const expectedEntries = getExpectedEntries();
25
+ let config = {};
26
+ if (fss.existsSync(hooksPath)) {
27
+ const raw = await fs.readFile(hooksPath, "utf8");
28
+ try {
29
+ config = JSON.parse(raw);
30
+ }
31
+ catch {
32
+ throw new Error(`Failed to parse ${hooksPath} — file is not valid JSON. Fix it manually before running init.`);
33
+ }
34
+ }
35
+ if (config.hooks !== undefined && (typeof config.hooks !== "object" || Array.isArray(config.hooks))) {
36
+ throw new Error(`${hooksPath} has invalid "hooks" field (expected object). Fix it manually before running init.`);
37
+ }
38
+ if (!config.hooks) {
39
+ config.hooks = {};
40
+ }
41
+ let changed = false;
42
+ for (const [eventType, newEntry] of Object.entries(expectedEntries)) {
43
+ const arr = config.hooks[eventType];
44
+ if (!arr) {
45
+ config.hooks[eventType] = [newEntry];
46
+ changed = true;
47
+ }
48
+ else if (Array.isArray(arr)) {
49
+ const apEntries = arr.filter(isAgentpilotEntry);
50
+ if (apEntries.length === 0) {
51
+ arr.push(newEntry);
52
+ changed = true;
53
+ }
54
+ else if (apEntries.length === 1) {
55
+ const idx = arr.indexOf(apEntries[0]);
56
+ if (JSON.stringify(arr[idx]) !== JSON.stringify(newEntry)) {
57
+ arr[idx] = newEntry;
58
+ changed = true;
59
+ }
60
+ }
61
+ else {
62
+ const firstIdx = arr.indexOf(apEntries[0]);
63
+ for (let i = apEntries.length - 1; i >= 1; i--) {
64
+ arr.splice(arr.indexOf(apEntries[i]), 1);
65
+ }
66
+ arr[firstIdx] = newEntry;
67
+ changed = true;
68
+ }
69
+ }
70
+ }
71
+ let backupPath = null;
72
+ if (changed) {
73
+ backupPath = await backupFile(hooksPath);
74
+ const content = JSON.stringify(config, null, 2) + "\n";
75
+ await writeFileLF(hooksPath, content);
76
+ await pruneBackups(hooksPath);
77
+ }
78
+ // Write hook scripts
79
+ const hookFiles = buildCursorFiles(webhookUrl);
80
+ for (const file of hookFiles) {
81
+ const filePath = path.join(projectDir, file.name);
82
+ await writeFileLF(filePath, file.content);
83
+ if (file.name.endsWith(".sh")) {
84
+ await chmodUnix(filePath, 0o755);
85
+ }
86
+ }
87
+ return { changed, backupPath, hooksPath };
88
+ }
89
+ //# sourceMappingURL=merge-cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-cursor.js","sourceRoot":"","sources":["../../src/lib/merge-cursor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function mergeWindsurf(projectDir: string, webhookUrl: string): Promise<{
2
+ changed: boolean;
3
+ backupPath: string | null;
4
+ hooksPath: string;
5
+ }>;