@orchagent/cli 0.3.72 → 0.3.74

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.
@@ -361,6 +361,64 @@ Edit \`main.py\` to customize:
361
361
 
362
362
  ## Environment Variables
363
363
 
364
+ | Variable | Required | Description |
365
+ |----------|----------|-------------|
366
+ | \`DISCORD_BOT_TOKEN\` | Yes | Discord bot token (workspace secret) |
367
+ | \`ANTHROPIC_API_KEY\` | Auto | Injected by orchagent via \`supported_providers\` |
368
+ | \`DISCORD_CHANNEL_IDS\` | Yes | Comma-separated channel IDs (workspace secret) |
369
+ | \`MODEL\` | No | Claude model (default: claude-sonnet-4-5-20250929) |
370
+ | \`MAX_TOKENS\` | No | Max response tokens (default: 1024) |
371
+ `;
372
+ }
373
+ if (flavor === 'discord_js') {
374
+ return `# ${agentName}
375
+
376
+ An always-on Discord bot powered by Claude (JavaScript).
377
+
378
+ ## Setup
379
+
380
+ ### 1. Create a Discord bot
381
+
382
+ 1. Go to the [Discord Developer Portal](https://discord.com/developers/applications)
383
+ 2. Create a new application, then go to **Bot** and copy the bot token
384
+ 3. Under **Privileged Gateway Intents**, enable **Message Content Intent**
385
+ 4. Go to **OAuth2 > URL Generator**, select \`bot\` scope, then invite to your server
386
+
387
+ ### 2. Get channel IDs
388
+
389
+ Enable Developer Mode in Discord (Settings > Advanced), then right-click a channel and copy its ID.
390
+
391
+ ### 3. Local development
392
+
393
+ \`\`\`sh
394
+ cp .env.example .env
395
+ # Fill in DISCORD_BOT_TOKEN, ANTHROPIC_API_KEY, DISCORD_CHANNEL_IDS
396
+
397
+ npm install
398
+ node main.js
399
+ \`\`\`
400
+
401
+ ### 4. Deploy
402
+
403
+ \`\`\`sh
404
+ orch publish
405
+
406
+ # Add secrets in your workspace (web dashboard > Settings > Secrets):
407
+ # DISCORD_BOT_TOKEN — your bot token
408
+ # DISCORD_CHANNEL_IDS — comma-separated channel IDs
409
+
410
+ orch service deploy
411
+ \`\`\`
412
+
413
+ ## Customization
414
+
415
+ Edit \`main.js\` to customize:
416
+
417
+ - **SYSTEM_PROMPT** — controls how the bot responds
418
+ - **MODEL** / **MAX_TOKENS** — override via env vars
419
+
420
+ ## Environment Variables
421
+
364
422
  | Variable | Required | Description |
365
423
  |----------|----------|-------------|
366
424
  | \`DISCORD_BOT_TOKEN\` | Yes | Discord bot token (workspace secret) |
@@ -1018,7 +1076,7 @@ function registerInitCommand(program) {
1018
1076
  await promises_1.default.writeFile(path_1.default.join(targetDir, 'main.js'), DISCORD_MAIN_JS);
1019
1077
  await promises_1.default.writeFile(path_1.default.join(targetDir, 'package.json'), DISCORD_PACKAGE_JSON);
1020
1078
  await promises_1.default.writeFile(path_1.default.join(targetDir, '.env.example'), DISCORD_JS_ENV_EXAMPLE);
1021
- await promises_1.default.writeFile(path_1.default.join(targetDir, 'README.md'), readmeTemplate(agentName, 'discord'));
1079
+ await promises_1.default.writeFile(path_1.default.join(targetDir, 'README.md'), readmeTemplate(agentName, 'discord_js'));
1022
1080
  const prefix = name ? name + '/' : '';
1023
1081
  process.stdout.write(`\nInitialized JS Discord bot "${agentName}" in ${targetDir}\n`);
1024
1082
  process.stdout.write(`\nFiles created:\n`);
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.extractTemplateVariables = extractTemplateVariables;
7
7
  exports.deriveInputSchema = deriveInputSchema;
8
8
  exports.scanUndeclaredEnvVars = scanUndeclaredEnvVars;
9
+ exports.detectSdkCompatible = detectSdkCompatible;
9
10
  exports.checkDependencies = checkDependencies;
10
11
  exports.registerPublishCommand = registerPublishCommand;
11
12
  const promises_1 = __importDefault(require("fs/promises"));
@@ -914,26 +915,30 @@ function registerPublishCommand(program) {
914
915
  catch {
915
916
  // Optional
916
917
  }
917
- // Include package.json + lockfile for JS agents (overrides DEFAULT_EXCLUDES)
918
- const pkgPath = path_1.default.join(cwd, 'package.json');
919
- try {
920
- await promises_1.default.access(pkgPath);
921
- includePatterns.push('package.json');
922
- process.stdout.write(` Including package.json for sandbox dependencies\n`);
923
- // Include lockfile for deterministic installs (npm ci)
924
- const lockPath = path_1.default.join(cwd, 'package-lock.json');
918
+ // Include package.json + lockfile for JS agents only (overrides DEFAULT_EXCLUDES)
919
+ // Guard on JS entrypoint to avoid bundling package.json for Python agents
920
+ // in mixed repos — the sandbox Python template lacks npm and would fail
921
+ if (bundleEntrypoint && bundleEntrypoint.endsWith('.js')) {
922
+ const pkgPath = path_1.default.join(cwd, 'package.json');
925
923
  try {
926
- await promises_1.default.access(lockPath);
927
- includePatterns.push('package-lock.json');
928
- process.stdout.write(` Including package-lock.json for deterministic installs\n`);
924
+ await promises_1.default.access(pkgPath);
925
+ includePatterns.push('package.json');
926
+ process.stdout.write(` Including package.json for sandbox dependencies\n`);
927
+ // Include lockfile for deterministic installs (npm ci)
928
+ const lockPath = path_1.default.join(cwd, 'package-lock.json');
929
+ try {
930
+ await promises_1.default.access(lockPath);
931
+ includePatterns.push('package-lock.json');
932
+ process.stdout.write(` Including package-lock.json for deterministic installs\n`);
933
+ }
934
+ catch {
935
+ // No lockfile — npm install will be used instead of npm ci
936
+ }
929
937
  }
930
938
  catch {
931
- // No lockfile — npm install will be used instead of npm ci
939
+ // No package.json
932
940
  }
933
941
  }
934
- catch {
935
- // No package.json — not a JS agent
936
- }
937
942
  }
938
943
  const bundleResult = await (0, bundle_1.createCodeBundle)(cwd, bundlePath, {
939
944
  entrypoint: bundleEntrypoint,
@@ -36,6 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.localCommandForEntrypoint = localCommandForEntrypoint;
39
40
  exports.isKeyedFileArg = isKeyedFileArg;
40
41
  exports.readKeyedFiles = readKeyedFiles;
41
42
  exports.mountDirectory = mountDirectory;
@@ -926,11 +927,12 @@ async function loadSkillPrompts(config, skillRefs, defaultOrg) {
926
927
  }
927
928
  return prompts;
928
929
  }
929
- function runCommand(command, args) {
930
+ function runCommand(command, args, options) {
930
931
  return new Promise((resolve) => {
931
932
  const proc = (0, child_process_1.spawn)(command, args, {
932
933
  stdio: ['inherit', 'pipe', 'pipe'],
933
934
  shell: true,
935
+ cwd: options?.cwd,
934
936
  });
935
937
  let stdout = '';
936
938
  let stderr = '';
@@ -1068,7 +1070,7 @@ async function executeBundleAgent(config, org, agentName, version, agentData, ar
1068
1070
  const npmArgs = useNpmCi
1069
1071
  ? ['ci', '--no-audit', '--no-fund']
1070
1072
  : ['install', '--production', '--no-audit', '--no-fund'];
1071
- const { code } = await runCommand('npm', npmArgs);
1073
+ const { code } = await runCommand('npm', npmArgs, { cwd: extractDir });
1072
1074
  if (code !== 0) {
1073
1075
  throw new errors_1.CliError('Failed to install npm dependencies');
1074
1076
  }
@@ -1529,7 +1531,7 @@ async function executeLocalFromDir(dirPath, args, options) {
1529
1531
  ? ['ci', '--no-audit', '--no-fund']
1530
1532
  : ['install', '--production', '--no-audit', '--no-fund'];
1531
1533
  process.stderr.write('Installing npm dependencies...\n');
1532
- const { code } = await runCommand('npm', npmArgs);
1534
+ const { code } = await runCommand('npm', npmArgs, { cwd: resolved });
1533
1535
  if (code !== 0) {
1534
1536
  process.stderr.write('Warning: Failed to install npm dependencies\n');
1535
1537
  }
@@ -43,6 +43,21 @@ function statusColor(status) {
43
43
  default: return status;
44
44
  }
45
45
  }
46
+ async function resolveScheduleId(config, partialId, workspaceId) {
47
+ // If it looks like a full UUID already, return as-is
48
+ if (partialId.length >= 32)
49
+ return partialId;
50
+ // Fetch schedules and match by prefix
51
+ const response = await (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/schedules?limit=200`);
52
+ const matches = response.schedules.filter((s) => s.id.startsWith(partialId));
53
+ if (matches.length === 0) {
54
+ throw new errors_1.CliError(`No schedule found matching '${partialId}'`);
55
+ }
56
+ if (matches.length > 1) {
57
+ throw new errors_1.CliError(`Ambiguous schedule ID '${partialId}' matches ${matches.length} schedules. Use a longer prefix.`);
58
+ }
59
+ return matches[0].id;
60
+ }
46
61
  // ============================================
47
62
  // COMMAND REGISTRATION
48
63
  // ============================================
@@ -283,12 +298,13 @@ function registerScheduleCommand(program) {
283
298
  .description('Manually trigger a schedule execution')
284
299
  .option('--input <json>', 'Override input data as JSON')
285
300
  .option('--workspace <slug>', 'Workspace slug (default: current workspace)')
286
- .action(async (scheduleId, options) => {
301
+ .action(async (partialScheduleId, options) => {
287
302
  const config = await (0, config_1.getResolvedConfig)();
288
303
  if (!config.apiKey) {
289
304
  throw new errors_1.CliError('Missing API key. Run `orch login` first.');
290
305
  }
291
306
  const workspaceId = await resolveWorkspaceId(config, options.workspace);
307
+ const scheduleId = await resolveScheduleId(config, partialScheduleId, workspaceId);
292
308
  let body;
293
309
  if (options.input) {
294
310
  try {
@@ -323,12 +339,13 @@ function registerScheduleCommand(program) {
323
339
  .description('Show detailed schedule information with recent runs and events')
324
340
  .option('--workspace <slug>', 'Workspace slug (default: current workspace)')
325
341
  .option('--json', 'Output as JSON')
326
- .action(async (scheduleId, options) => {
342
+ .action(async (partialScheduleId, options) => {
327
343
  const config = await (0, config_1.getResolvedConfig)();
328
344
  if (!config.apiKey) {
329
345
  throw new errors_1.CliError('Missing API key. Run `orch login` first.');
330
346
  }
331
347
  const workspaceId = await resolveWorkspaceId(config, options.workspace);
348
+ const scheduleId = await resolveScheduleId(config, partialScheduleId, workspaceId);
332
349
  const [scheduleRes, runsRes, eventsRes] = await Promise.all([
333
350
  (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/schedules/${scheduleId}`),
334
351
  (0, api_1.request)(config, 'GET', `/workspaces/${workspaceId}/schedules/${scheduleId}/runs?limit=5`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchagent/cli",
3
- "version": "0.3.72",
3
+ "version": "0.3.74",
4
4
  "description": "Command-line interface for orchagent — deploy and run AI agents for your team",
5
5
  "license": "MIT",
6
6
  "author": "orchagent <hello@orchagent.io>",