@octp/cli 0.1.6 → 0.1.8

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.
@@ -0,0 +1,297 @@
1
+ import { Command } from "commander";
2
+ import { hostname, homedir } from "node:os";
3
+ import { existsSync, writeFileSync, mkdirSync } from "node:fs";
4
+ import { execSync, spawn } from "node:child_process";
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import chalk from "chalk";
8
+ import { apiPost, apiGet } from "../../lib/api-client.js";
9
+ import { getApiToken } from "../../lib/config-store.js";
10
+ import { success, error, warn, info } from "../../lib/output.js";
11
+ import { loadWatchConfig } from "./watch.js";
12
+ import { semanticSearch, grepSearch, fileReadSearch } from "./searcher.js";
13
+ import { hasClaudeCli, claudeSearch } from "./claude-searcher.js";
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ function parseGitRemote(url) {
16
+ const sshMatch = url.match(/git@[^:]+:([^/]+\/[^/]+?)(?:\.git)?$/);
17
+ if (sshMatch)
18
+ return sshMatch[1];
19
+ const httpsMatch = url.match(/https?:\/\/[^/]+\/([^/]+\/[^/]+?)(?:\.git)?$/);
20
+ if (httpsMatch)
21
+ return httpsMatch[1];
22
+ return null;
23
+ }
24
+ function getGitRemoteUrl(dirPath) {
25
+ try {
26
+ return execSync("git remote get-url origin", {
27
+ cwd: dirPath,
28
+ encoding: "utf-8",
29
+ stdio: ["pipe", "pipe", "pipe"],
30
+ }).trim();
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * Resolve watched directories to repo mappings.
38
+ */
39
+ function resolveWatchedRepos() {
40
+ const config = loadWatchConfig();
41
+ const repoMap = new Map(); // repoFullName -> localPath
42
+ for (const entry of config.entries) {
43
+ if (!existsSync(entry.path)) {
44
+ warn(`Skipping ${entry.path} — directory not found`);
45
+ continue;
46
+ }
47
+ const remoteUrl = getGitRemoteUrl(entry.path);
48
+ if (!remoteUrl) {
49
+ warn(`Skipping ${entry.path} — no git remote`);
50
+ continue;
51
+ }
52
+ const fullName = parseGitRemote(remoteUrl);
53
+ if (!fullName) {
54
+ warn(`Skipping ${entry.path} — could not parse remote: ${remoteUrl}`);
55
+ continue;
56
+ }
57
+ repoMap.set(fullName, entry.path);
58
+ }
59
+ return repoMap;
60
+ }
61
+ export const startCommand = new Command("start")
62
+ .description("Start the local agent daemon")
63
+ .option("--with-claude", "Enable Claude CLI for deep semantic search")
64
+ .option("--verbose", "Run in foreground with detailed logs")
65
+ .option("--foreground", "Run in foreground (without verbose logs)")
66
+ .action(async (opts) => {
67
+ const token = getApiToken();
68
+ if (!token) {
69
+ error("Not logged in. Run 'octopus login' first.");
70
+ process.exit(1);
71
+ }
72
+ const runInForeground = opts.verbose || opts.foreground;
73
+ // Default: background mode — spawn detached child and exit
74
+ if (!runInForeground) {
75
+ const binPath = join(__dirname, "..", "..", "..", "bin", "octopus.js");
76
+ if (!existsSync(binPath)) {
77
+ error(`Could not locate agent binary at: ${binPath}`);
78
+ process.exit(1);
79
+ }
80
+ const args = [binPath, "agent", "start", "--foreground"];
81
+ if (opts.withClaude)
82
+ args.push("--with-claude");
83
+ const child = spawn(process.execPath, args, {
84
+ detached: true,
85
+ stdio: "ignore",
86
+ });
87
+ child.on("error", (err) => {
88
+ error(`Failed to start background agent: ${err.message}`);
89
+ process.exit(1);
90
+ });
91
+ child.unref();
92
+ // Write PID file for manageability
93
+ const pidDir = join(homedir(), ".octopus");
94
+ mkdirSync(pidDir, { recursive: true });
95
+ const pidFile = join(pidDir, "agent.pid");
96
+ writeFileSync(pidFile, String(child.pid));
97
+ success(`Agent started in background (PID: ${child.pid})`);
98
+ info(`PID saved to ${pidFile}. To stop: kill $(cat ${pidFile})`);
99
+ process.exit(0);
100
+ }
101
+ // Resolve watched repos
102
+ const repoMap = resolveWatchedRepos();
103
+ if (repoMap.size === 0) {
104
+ error("No watched repos found. Run 'octopus agent watch' in a repo directory first.");
105
+ process.exit(1);
106
+ }
107
+ const repoFullNames = [...repoMap.keys()];
108
+ info(`Found ${repoMap.size} watched repo(s):`);
109
+ for (const [name, path] of repoMap) {
110
+ console.log(` ${chalk.cyan(name)} → ${path}`);
111
+ }
112
+ // Check Claude CLI availability
113
+ const claudeAvailable = opts.withClaude ? hasClaudeCli() : false;
114
+ if (opts.withClaude && !claudeAvailable) {
115
+ warn("Claude CLI not found. Falling back to ripgrep mode.");
116
+ }
117
+ const capabilities = ["code-search"]; // ripgrep or Node.js fallback
118
+ if (claudeAvailable)
119
+ capabilities.push("claude-cli");
120
+ const agentName = `${hostname()}-${process.pid}`;
121
+ // Register with server
122
+ let agentId;
123
+ let orgId;
124
+ try {
125
+ const res = await apiPost("/api/agent/register", {
126
+ name: agentName,
127
+ repoFullNames,
128
+ capabilities,
129
+ machineInfo: {
130
+ os: process.platform,
131
+ hostname: hostname(),
132
+ nodeVersion: process.version,
133
+ },
134
+ });
135
+ agentId = res.agentId;
136
+ orgId = res.orgId;
137
+ success(`Registered as "${agentName}" (${capabilities.join(", ")})`);
138
+ }
139
+ catch (err) {
140
+ error(`Failed to register: ${err instanceof Error ? err.message : err}`);
141
+ process.exit(1);
142
+ }
143
+ const verbose = opts.verbose ?? false;
144
+ // Heartbeat interval
145
+ const heartbeatInterval = setInterval(async () => {
146
+ try {
147
+ // Re-scan repos in case they changed
148
+ const freshMap = resolveWatchedRepos();
149
+ const freshNames = [...freshMap.keys()];
150
+ // Update our local map
151
+ for (const [name, path] of freshMap) {
152
+ repoMap.set(name, path);
153
+ }
154
+ await apiPost("/api/agent/heartbeat", {
155
+ agentId,
156
+ repoFullNames: freshNames,
157
+ });
158
+ if (verbose) {
159
+ info(`Heartbeat sent (${freshNames.length} repos)`);
160
+ }
161
+ }
162
+ catch (err) {
163
+ if (verbose) {
164
+ warn(`Heartbeat failed: ${err instanceof Error ? err.message : err}`);
165
+ }
166
+ }
167
+ }, 30_000);
168
+ // Task polling interval (fallback for missed Pubby signals)
169
+ const pollInterval = setInterval(async () => {
170
+ try {
171
+ const res = await apiGet(`/api/agent/tasks?agentId=${agentId}`);
172
+ if (verbose && res.tasks.length > 0) {
173
+ info(`Received ${res.tasks.length} task(s)`);
174
+ }
175
+ for (const task of res.tasks) {
176
+ handleTask(task, repoMap, agentId, claudeAvailable, verbose);
177
+ }
178
+ }
179
+ catch (err) {
180
+ if (verbose) {
181
+ warn(`Poll failed: ${err instanceof Error ? err.message : err}`);
182
+ }
183
+ }
184
+ }, 2_000);
185
+ // Graceful shutdown
186
+ const cleanup = async () => {
187
+ console.log("\n");
188
+ info("Shutting down...");
189
+ clearInterval(heartbeatInterval);
190
+ clearInterval(pollInterval);
191
+ try {
192
+ await apiPost("/api/agent/disconnect", { agentId });
193
+ success("Disconnected.");
194
+ }
195
+ catch { }
196
+ process.exit(0);
197
+ };
198
+ process.on("SIGINT", cleanup);
199
+ process.on("SIGTERM", cleanup);
200
+ console.log("");
201
+ success(`Agent running. Listening for search requests...`);
202
+ if (verbose) {
203
+ info("Verbose mode enabled — showing all activity logs.");
204
+ info(`Agent ID: ${agentId}`);
205
+ info(`Repos: ${repoFullNames.join(", ")}`);
206
+ info(`Polling every 2s, heartbeat every 30s`);
207
+ info(`Press Ctrl+C to stop.\n`);
208
+ }
209
+ else {
210
+ info(`Press Ctrl+C to stop.\n`);
211
+ }
212
+ });
213
+ /**
214
+ * Handle a single search task — claim, execute, submit result.
215
+ */
216
+ async function handleTask(task, repoMap, agentId, claudeAvailable, verbose) {
217
+ const repoDir = repoMap.get(task.repoFullName);
218
+ if (!repoDir)
219
+ return;
220
+ // Claim the task
221
+ try {
222
+ await apiPost(`/api/agent/tasks/${task.id}/claim`, { agentId });
223
+ }
224
+ catch {
225
+ // Already claimed by another agent
226
+ return;
227
+ }
228
+ if (verbose) {
229
+ info(`Claimed task ${task.id}: "${task.query}" (${task.searchType}) in ${task.repoFullName}`);
230
+ }
231
+ try {
232
+ let resultSummary;
233
+ switch (task.searchType) {
234
+ case "claude": {
235
+ if (claudeAvailable) {
236
+ try {
237
+ resultSummary = await claudeSearch(task.query, repoDir, task.timeoutMs - 2000);
238
+ }
239
+ catch {
240
+ // Fall back to semantic search
241
+ if (verbose)
242
+ warn("Claude CLI failed, falling back to ripgrep");
243
+ const { summary } = await semanticSearch(task.query, repoDir);
244
+ resultSummary = summary;
245
+ }
246
+ }
247
+ else {
248
+ const { summary } = await semanticSearch(task.query, repoDir);
249
+ resultSummary = summary;
250
+ }
251
+ break;
252
+ }
253
+ case "grep": {
254
+ const pattern = task.params.pattern ?? task.query;
255
+ const { summary } = await grepSearch(pattern, repoDir);
256
+ resultSummary = summary;
257
+ break;
258
+ }
259
+ case "file-read": {
260
+ const filePaths = task.params.filePaths ?? [];
261
+ const { summary } = await fileReadSearch(filePaths, repoDir);
262
+ resultSummary = summary;
263
+ break;
264
+ }
265
+ case "semantic":
266
+ default: {
267
+ const { summary } = await semanticSearch(task.query, repoDir);
268
+ resultSummary = summary;
269
+ break;
270
+ }
271
+ }
272
+ // Submit results
273
+ await apiPost(`/api/agent/tasks/${task.id}/result`, {
274
+ results: [],
275
+ resultSummary,
276
+ });
277
+ if (verbose) {
278
+ success(`Completed task ${task.id} (${resultSummary.length} chars)`);
279
+ }
280
+ else {
281
+ console.log(`${chalk.green("✓")} Searched "${task.query.slice(0, 50)}${task.query.length > 50 ? "..." : ""}" in ${chalk.cyan(task.repoFullName)}`);
282
+ }
283
+ }
284
+ catch (err) {
285
+ // Submit error
286
+ try {
287
+ await apiPost(`/api/agent/tasks/${task.id}/result`, {
288
+ errorMessage: err instanceof Error ? err.message : "Unknown error",
289
+ });
290
+ }
291
+ catch { }
292
+ if (verbose) {
293
+ error(`Task ${task.id} failed: ${err instanceof Error ? err.message : err}`);
294
+ }
295
+ }
296
+ }
297
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/commands/agent/start.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { Command } from "commander";
2
+ interface WatchEntry {
3
+ path: string;
4
+ remoteUrl: string;
5
+ repoFullName: string;
6
+ addedAt: string;
7
+ }
8
+ interface WatchConfig {
9
+ entries: WatchEntry[];
10
+ }
11
+ declare function loadWatchConfig(): WatchConfig;
12
+ export { loadWatchConfig, type WatchEntry };
13
+ export declare const watchCommand: Command;
@@ -0,0 +1,142 @@
1
+ import { Command } from "commander";
2
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
3
+ import { execSync, spawn } from "node:child_process";
4
+ import { resolve, join, dirname } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { homedir } from "node:os";
7
+ import chalk from "chalk";
8
+ import { success, error, warn, info, heading, table } from "../../lib/output.js";
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const CONFIG_DIR = join(homedir(), ".octopus");
11
+ const WATCH_FILE = join(CONFIG_DIR, "agent-watch.json");
12
+ function loadWatchConfig() {
13
+ try {
14
+ const data = readFileSync(WATCH_FILE, "utf-8");
15
+ return JSON.parse(data);
16
+ }
17
+ catch {
18
+ return { entries: [] };
19
+ }
20
+ }
21
+ function saveWatchConfig(config) {
22
+ if (!existsSync(CONFIG_DIR)) {
23
+ mkdirSync(CONFIG_DIR, { recursive: true });
24
+ }
25
+ writeFileSync(WATCH_FILE, JSON.stringify(config, null, 2));
26
+ }
27
+ function getGitRemoteUrl(dirPath) {
28
+ try {
29
+ return execSync("git remote get-url origin", {
30
+ cwd: dirPath,
31
+ encoding: "utf-8",
32
+ stdio: ["pipe", "pipe", "pipe"],
33
+ }).trim();
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ function parseGitRemote(url) {
40
+ // SSH: git@github.com:owner/repo.git
41
+ const sshMatch = url.match(/git@[^:]+:([^/]+\/[^/]+?)(?:\.git)?$/);
42
+ if (sshMatch)
43
+ return sshMatch[1];
44
+ // HTTPS: https://github.com/owner/repo.git
45
+ const httpsMatch = url.match(/https?:\/\/[^/]+\/([^/]+\/[^/]+?)(?:\.git)?$/);
46
+ if (httpsMatch)
47
+ return httpsMatch[1];
48
+ return null;
49
+ }
50
+ export { loadWatchConfig };
51
+ export const watchCommand = new Command("watch")
52
+ .description("Manage watched directories for local agent")
53
+ .argument("[path]", "Directory to watch (defaults to current directory)")
54
+ .option("--list", "List all watched directories")
55
+ .option("--remove", "Remove directory from watch list")
56
+ .option("--no-start", "Don't auto-start the agent after adding")
57
+ .option("--verbose", "Start agent in foreground with detailed logs")
58
+ .action(async (pathArg, opts) => {
59
+ if (opts.list) {
60
+ const config = loadWatchConfig();
61
+ if (config.entries.length === 0) {
62
+ info("No watched directories. Run 'octopus agent watch' in a repo directory to add one.");
63
+ return;
64
+ }
65
+ heading("Watched Directories");
66
+ const rows = config.entries.map((entry) => {
67
+ const exists = existsSync(entry.path);
68
+ const status = exists ? chalk.green("ok") : chalk.red("missing");
69
+ return [entry.path, chalk.cyan(entry.repoFullName), status];
70
+ });
71
+ table(rows, ["Path", "Repository", "Status"]);
72
+ return;
73
+ }
74
+ const targetPath = resolve(pathArg ?? ".");
75
+ if (opts.remove) {
76
+ const config = loadWatchConfig();
77
+ const before = config.entries.length;
78
+ config.entries = config.entries.filter((e) => e.path !== targetPath);
79
+ if (config.entries.length === before) {
80
+ warn(`${targetPath} is not in the watch list.`);
81
+ return;
82
+ }
83
+ saveWatchConfig(config);
84
+ success(`Removed ${targetPath} from watch list.`);
85
+ return;
86
+ }
87
+ // Add directory to watch list
88
+ if (!existsSync(targetPath)) {
89
+ error(`Directory not found: ${targetPath}`);
90
+ process.exit(1);
91
+ }
92
+ const remoteUrl = getGitRemoteUrl(targetPath);
93
+ if (!remoteUrl) {
94
+ error(`No git remote found in ${targetPath}. Is this a git repository?`);
95
+ process.exit(1);
96
+ }
97
+ const repoFullName = parseGitRemote(remoteUrl);
98
+ if (!repoFullName) {
99
+ error(`Could not parse git remote URL: ${remoteUrl}`);
100
+ process.exit(1);
101
+ }
102
+ const config = loadWatchConfig();
103
+ // Check for duplicates
104
+ const existing = config.entries.find((e) => e.path === targetPath);
105
+ if (existing) {
106
+ if (existing.repoFullName === repoFullName) {
107
+ info(`${targetPath} is already watched as ${chalk.cyan(repoFullName)}.`);
108
+ return;
109
+ }
110
+ // Update remote if changed
111
+ existing.remoteUrl = remoteUrl;
112
+ existing.repoFullName = repoFullName;
113
+ saveWatchConfig(config);
114
+ success(`Updated ${targetPath} → ${chalk.cyan(repoFullName)} (via git remote)`);
115
+ return;
116
+ }
117
+ config.entries.push({
118
+ path: targetPath,
119
+ remoteUrl,
120
+ repoFullName,
121
+ addedAt: new Date().toISOString(),
122
+ });
123
+ saveWatchConfig(config);
124
+ success(`Added ${targetPath} → ${chalk.cyan(repoFullName)} (via git remote)`);
125
+ if (opts.start !== false) {
126
+ info("Starting agent...\n");
127
+ const binPath = join(__dirname, "..", "..", "..", "bin", "octopus.js");
128
+ const args = [binPath, "agent", "start"];
129
+ if (opts.verbose)
130
+ args.push("--verbose");
131
+ const child = spawn(process.execPath, args, {
132
+ stdio: "inherit",
133
+ });
134
+ await new Promise((resolve) => {
135
+ child.on("close", (code) => {
136
+ process.exit(code ?? 0);
137
+ resolve();
138
+ });
139
+ });
140
+ }
141
+ });
142
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../src/commands/agent/watch.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,6 @@
1
1
  import { Command } from "commander";
2
+ export declare function reviewAction(prArg: string | undefined, opts: {
3
+ pr?: string;
4
+ }): Promise<void>;
5
+ export declare const PR_ARG_DESC = "PR number or URL (e.g. 123 or https://github.com/owner/repo/pull/123)";
2
6
  export declare const prReviewCommand: Command;
@@ -26,13 +26,15 @@ function parsePrArg(arg) {
26
26
  }
27
27
  throw new Error(`Invalid PR identifier: "${arg}". Use a PR number or URL.`);
28
28
  }
29
- export const prReviewCommand = new Command("review")
30
- .argument("<pr>", "PR number or URL (e.g. 123 or https://github.com/owner/repo/pull/123)")
31
- .description("Trigger an AI review on a pull request")
32
- .action(async (prArg) => {
29
+ export async function reviewAction(prArg, opts) {
30
+ const resolved = prArg ?? opts.pr;
31
+ if (!resolved) {
32
+ error("Missing PR identifier. Usage: octopus review <pr> or octopus review --pr <pr>");
33
+ process.exit(1);
34
+ }
33
35
  try {
34
36
  const spinner = createSpinner("Resolving pull request...").start();
35
- const { prNumber, repoFullName } = parsePrArg(prArg);
37
+ const { prNumber, repoFullName } = parsePrArg(resolved);
36
38
  const repo = await resolveRepo(repoFullName);
37
39
  spinner.text = `Starting review for ${repo.fullName} PR #${prNumber}...`;
38
40
  await apiPost(`/api/cli/repos/${repo.id}/review`, { prNumber });
@@ -43,5 +45,11 @@ export const prReviewCommand = new Command("review")
43
45
  error(err instanceof Error ? err.message : "Failed to trigger review");
44
46
  process.exit(1);
45
47
  }
46
- });
48
+ }
49
+ export const PR_ARG_DESC = "PR number or URL (e.g. 123 or https://github.com/owner/repo/pull/123)";
50
+ export const prReviewCommand = new Command("review")
51
+ .argument("[pr]", PR_ARG_DESC)
52
+ .option("--pr <pr>", PR_ARG_DESC)
53
+ .description("Trigger an AI review on a pull request")
54
+ .action(reviewAction);
47
55
  //# sourceMappingURL=review.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/commands/pr/review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAW,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD;;;;GAIG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,kBAAkB;IAClB,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAChB,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IAC3B,CAAC;IAED,sBAAsB;IACtB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACpE,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,CAAC;IAED,yBAAyB;IACzB,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAClF,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,4BAA4B,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KACjD,QAAQ,CAAC,MAAM,EAAE,uEAAuE,CAAC;KACzF,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,EAAE;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,2BAA2B,CAAC,CAAC,KAAK,EAAE,CAAC;QACnE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAErD,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,GAAG,uBAAuB,IAAI,CAAC,QAAQ,QAAQ,QAAQ,KAAK,CAAC;QAEzE,MAAM,OAAO,CAAC,kBAAkB,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChE,OAAO,CAAC,OAAO,CAAC,wBAAwB,IAAI,CAAC,QAAQ,QAAQ,QAAQ,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,iEAAiE,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/commands/pr/review.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,3 @@
1
1
  import { Command } from "commander";
2
+ export declare function checkSkillUpdates(): Promise<void>;
2
3
  export declare const skillsCommand: Command;