codeply-cli 0.3.0 → 0.3.1

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.
package/bin/codeply.js CHANGED
@@ -509,13 +509,9 @@ githubCmd
509
509
  let event;
510
510
  try { event = JSON.parse(fs.readFileSync(cfg.GITHUB_EVENT_PATH, 'utf8')); } catch (e) { console.error(c.red(`Could not read the event: ${e.message}`)); process.exitCode = 1; return; }
511
511
  const r = g.routeFromEnv(cfg);
512
- if (r.error) {
513
- console.error(c.red(r.error));
514
- process.exitCode = 1;
515
- return;
516
- }
512
+ // A setup error is still reported on the issue, so the person who asked isn't left waiting.
517
513
  const out = await g.runGithubAgent({
518
- eventName: cfg.GITHUB_EVENT_NAME, event, token, route: r.route, env: cfg, cwd: process.cwd(),
514
+ eventName: cfg.GITHUB_EVENT_NAME, event, token, route: r.route, setupError: r.error, env: cfg, cwd: process.cwd(),
519
515
  maxSteps: Math.max(1, Number(opts.maxSteps) || 40), log: (m) => console.log(m),
520
516
  });
521
517
  console.log(`${out.status}${out.url ? ` ${out.url}` : ''}`);
@@ -31,6 +31,7 @@ const DEFAULT_ALLOWED = ['OWNER', 'MEMBER', 'COLLABORATOR'];
31
31
  const MAX_COMMENT = 60000;
32
32
 
33
33
  export const PROVIDERS = {
34
+ ollama: { baseUrl: 'https://ollama.com/v1', model: 'gemma4:31b' },
34
35
  openai: { baseUrl: 'https://api.openai.com/v1', model: 'gpt-4o-mini' },
35
36
  anthropic: { baseUrl: 'https://api.anthropic.com/v1', model: 'claude-sonnet-5' },
36
37
  gemini: { baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai', model: 'gemini-3.7-flash' },
@@ -48,8 +49,10 @@ export function routeFromEnv(env) {
48
49
  const model = env.CODEPLY_MODEL || (preset && preset.model);
49
50
  if (!model) return { error: 'Set CODEPLY_MODEL.' };
50
51
  const local = /^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])/.test(baseUrl);
51
- if (!env.CODEPLY_API_KEY && !local) return { error: 'Set the CODEPLY_API_KEY secret (your own key for the model provider).' };
52
- return { route: { custom: { id: 'github', name: model, kind: 'openai', baseUrl, model, apiKey: env.CODEPLY_API_KEY || '' } } };
52
+ // Keys pasted on Windows often carry a BOM or a trailing newline, which fetch rejects in a header.
53
+ const apiKey = String(env.CODEPLY_API_KEY || '').replace(/[\s]/g, '');
54
+ if (!apiKey && !local) return { error: 'Set the CODEPLY_API_KEY secret (your own key for the model provider).' };
55
+ return { route: { custom: { id: 'github', name: model, kind: 'openai', baseUrl, model, apiKey } } };
53
56
  }
54
57
 
55
58
  /** What the event asks for, or why to skip it. */
@@ -142,7 +145,7 @@ function buildPrompt(ctx, repo, pr) {
142
145
  * @returns {Promise<{status: 'skipped'|'answered'|'pushed'|'pr'|'failed', message?: string, url?: string}>}
143
146
  */
144
147
  export async function runGithubAgent({
145
- eventName, event, cwd = process.cwd(), token, route, env = process.env, maxSteps = 40,
148
+ eventName, event, cwd = process.cwd(), token, route, setupError = null, env = process.env, maxSteps = 40,
146
149
  fetchImpl = fetch, log = () => {}, runAgentImpl = runAgent,
147
150
  }) {
148
151
  const allowed = env.CODEPLY_ALLOWED_ASSOCIATIONS ? env.CODEPLY_ALLOWED_ASSOCIATIONS.split(',').map((s) => s.trim().toUpperCase()).filter(Boolean) : DEFAULT_ALLOWED;
@@ -166,6 +169,11 @@ export async function runGithubAgent({
166
169
  } catch (e) { log(`Could not post a comment: ${e.message}`); }
167
170
  };
168
171
 
172
+ if (setupError) {
173
+ await say(`Craft can't start yet: ${setupError}`);
174
+ return { status: 'failed', message: setupError };
175
+ }
176
+
169
177
  try {
170
178
  if (ctx.commentId) await api('POST', `/repos/${repo}/${ctx.commentKind === 'review' ? 'pulls' : 'issues'}/comments/${ctx.commentId}/reactions`, { content: 'eyes' }).catch(() => {});
171
179
  await say(`Working on it (${ctx.mode === 'Build' ? 'build' : ctx.mode.toLowerCase()} mode)...`);
@@ -227,10 +235,19 @@ export async function runGithubAgent({
227
235
  await say(`${answer}\n\nPushed ${changed} changed file${changed === 1 ? '' : 's'} to \`${branch}\` (${sha}).`);
228
236
  return { status: 'pushed', message: answer, url: `${serverUrl}/${repo}/commit/${sha}` };
229
237
  }
230
- const made = await api('POST', `/repos/${repo}/pulls`, {
231
- title: ctx.title ? `Fix: ${ctx.title}`.slice(0, 120) : subject, head: branch, base,
232
- body: `${answer}\n\nCloses #${ctx.number}\n\n<sub>Opened by Codeply Craft at @${ctx.author}'s request.</sub>`,
233
- });
238
+ let made;
239
+ try {
240
+ made = await api('POST', `/repos/${repo}/pulls`, {
241
+ title: ctx.title ? `Fix: ${ctx.title}`.slice(0, 120) : subject, head: branch, base,
242
+ body: `${answer}\n\nCloses #${ctx.number}\n\n<sub>Opened by Codeply Craft at @${ctx.author}'s request.</sub>`,
243
+ });
244
+ } catch (e) {
245
+ // New repos block Actions from opening PRs; the branch is pushed, so hand over a one-click link.
246
+ if (!/not permitted to create/i.test(e.message)) throw e;
247
+ const compare = `${serverUrl}/${repo}/compare/${base}...${encodeURIComponent(branch)}?expand=1`;
248
+ await say(`${answer}\n\nPushed ${changed} changed file${changed === 1 ? '' : 's'} to \`${branch}\` (${sha}). [Open the pull request](${compare}).\n\nTo let Craft open pull requests itself, turn on Settings > Actions > General > "Allow GitHub Actions to create and approve pull requests".`);
249
+ return { status: 'pushed', message: answer, url: compare };
250
+ }
234
251
  await say(`${answer}\n\nOpened ${made.html_url} (${changed} changed file${changed === 1 ? '' : 's'}, ${steps} steps).`);
235
252
  return { status: 'pr', message: answer, url: made.html_url };
236
253
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeply-cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Codeply from the terminal: an interactive AI coding agent, a local server (codeply serve), and a GitHub agent that runs in your own Actions runner.",
5
5
  "main": "bin/codeply.js",
6
6
  "bin": {