@vm0/cli 9.92.1 → 9.94.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.
package/zero.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  EventRenderer,
6
6
  MODEL_PROVIDER_TYPES,
7
7
  allowsCustomModel,
8
+ completeSlackFileUpload,
8
9
  configureGlobalProxyFromEnv,
9
10
  connectorTypeSchema,
10
11
  createSkill,
@@ -58,6 +59,7 @@ import {
58
59
  hasAuthMethods,
59
60
  hasModelSelection,
60
61
  hasRequiredScopes,
62
+ initSlackFileUpload,
61
63
  inviteZeroOrgMember,
62
64
  isFeatureEnabled,
63
65
  isFirewallConnectorType,
@@ -100,10 +102,10 @@ import {
100
102
  updateZeroUserPreferences,
101
103
  upsertZeroOrgModelProvider,
102
104
  withErrorHandler
103
- } from "./chunk-KXR4BFFL.js";
105
+ } from "./chunk-XQIPEDKM.js";
104
106
 
105
107
  // src/zero.ts
106
- import { Command as Command68 } from "commander";
108
+ import { Command as Command70 } from "commander";
107
109
 
108
110
  // src/commands/zero/org/index.ts
109
111
  import { Command as Command23 } from "commander";
@@ -227,10 +229,21 @@ var membersCommand = new Command5().name("members").description("View organizati
227
229
  // src/commands/zero/org/invite.ts
228
230
  import { Command as Command6 } from "commander";
229
231
  import chalk6 from "chalk";
230
- var inviteCommand = new Command6().name("invite").description("Invite a member to the current organization").requiredOption("--email <email>", "Email address of the member to invite").action(
232
+ var inviteCommand = new Command6().name("invite").description("Invite a member to the current organization").requiredOption("--email <email>", "Email address of the member to invite").option(
233
+ "--role <role>",
234
+ "Role for the invited member (member or admin)",
235
+ "member"
236
+ ).action(
231
237
  withErrorHandler(async (options) => {
232
- await inviteZeroOrgMember(options.email);
233
- console.log(chalk6.green(`\u2713 Invitation sent to ${options.email}`));
238
+ if (options.role !== "member" && options.role !== "admin") {
239
+ throw new Error(
240
+ `Invalid role "${options.role}". Must be "member" or "admin".`
241
+ );
242
+ }
243
+ await inviteZeroOrgMember(options.email, options.role);
244
+ console.log(
245
+ chalk6.green(`\u2713 Invitation sent to ${options.email} as ${options.role}`)
246
+ );
234
247
  })
235
248
  );
236
249
 
@@ -2017,7 +2030,7 @@ var disconnectCommand = new Command33().name("disconnect").description("Disconne
2017
2030
  var zeroConnectorCommand = new Command34().name("connector").description("Check or connect third-party services (GitHub, Slack, etc.)").addCommand(listCommand6).addCommand(statusCommand2).addCommand(connectCommand).addCommand(disconnectCommand);
2018
2031
 
2019
2032
  // src/commands/zero/doctor/index.ts
2020
- import { Command as Command37 } from "commander";
2033
+ import { Command as Command38 } from "commander";
2021
2034
 
2022
2035
  // src/commands/zero/doctor/missing-token.ts
2023
2036
  import { Command as Command35 } from "commander";
@@ -2114,6 +2127,22 @@ Notes:
2114
2127
 
2115
2128
  // src/commands/zero/doctor/firewall-deny.ts
2116
2129
  import { Command as Command36, Option } from "commander";
2130
+
2131
+ // src/commands/zero/doctor/resolve-role.ts
2132
+ async function resolveRole() {
2133
+ try {
2134
+ const org = await getZeroOrg();
2135
+ if (org.role === "admin" || org.role === "member") {
2136
+ return org.role;
2137
+ }
2138
+ return "unknown";
2139
+ } catch (error) {
2140
+ console.debug("resolveRole failed, falling back to unknown:", error);
2141
+ return "unknown";
2142
+ }
2143
+ }
2144
+
2145
+ // src/commands/zero/doctor/firewall-deny.ts
2117
2146
  var firewallDenyCommand = new Command36().name("firewall-deny").description(
2118
2147
  "Diagnose a firewall denial and find the permission that covers it"
2119
2148
  ).argument("<firewall-ref>", "The firewall connector type (e.g. github)").addOption(
@@ -2179,20 +2208,116 @@ Notes:
2179
2208
  );
2180
2209
  console.log("");
2181
2210
  }
2182
- console.log(
2183
- `Ask the user to allow it at: [Allow ${label} access](${url})`
2184
- );
2211
+ const role = agentId ? await resolveRole() : "unknown";
2212
+ if (role === "admin") {
2213
+ console.log(
2214
+ `You can allow this permission directly: [Manage ${label} firewall](${url})`
2215
+ );
2216
+ } else if (role === "member") {
2217
+ console.log(
2218
+ `This change requires admin approval. Request access at: [Request ${label} access](${url})`
2219
+ );
2220
+ } else {
2221
+ console.log(
2222
+ `Ask the user to allow it at: [Allow ${label} access](${url})`
2223
+ );
2224
+ }
2225
+ }
2226
+ )
2227
+ );
2228
+
2229
+ // src/commands/zero/doctor/firewall-permissions-change.ts
2230
+ import { Command as Command37, Option as Option2 } from "commander";
2231
+ function findPermissionInConfig(ref, permissionName) {
2232
+ if (!isFirewallConnectorType(ref)) return false;
2233
+ const config = getConnectorFirewall(ref);
2234
+ for (const api of config.apis) {
2235
+ if (!api.permissions) continue;
2236
+ for (const p of api.permissions) {
2237
+ if (p.name === permissionName) return true;
2238
+ }
2239
+ }
2240
+ return false;
2241
+ }
2242
+ var firewallPermissionsChangeCommand = new Command37().name("firewall-permissions-change").description("Request a firewall permission change (enable or disable)").argument("<firewall-ref>", "The firewall connector type (e.g. github)").addOption(
2243
+ new Option2(
2244
+ "--permission <name>",
2245
+ "The permission name to change"
2246
+ ).makeOptionMandatory()
2247
+ ).addOption(
2248
+ new Option2("--enable", "Request to enable the permission").conflicts(
2249
+ "disable"
2250
+ )
2251
+ ).addOption(
2252
+ new Option2("--disable", "Request to disable the permission").conflicts(
2253
+ "enable"
2254
+ )
2255
+ ).addHelpText(
2256
+ "after",
2257
+ `
2258
+ Examples:
2259
+ zero doctor firewall-permissions-change github --permission contents:read --enable
2260
+ zero doctor firewall-permissions-change slack --permission chat:write --disable
2261
+
2262
+ Notes:
2263
+ - Outputs a platform URL for the user to adjust the permission
2264
+ - Admins can change permissions directly; members must request approval`
2265
+ ).action(
2266
+ withErrorHandler(
2267
+ async (firewallRef, opts) => {
2268
+ if (!opts.enable && !opts.disable) {
2269
+ throw new Error("Either --enable or --disable is required");
2270
+ }
2271
+ if (!isFirewallConnectorType(firewallRef)) {
2272
+ throw new Error(`Unknown firewall connector type: ${firewallRef}`);
2273
+ }
2274
+ if (!findPermissionInConfig(firewallRef, opts.permission)) {
2275
+ throw new Error(
2276
+ `Unknown permission "${opts.permission}" for ${firewallRef} firewall`
2277
+ );
2278
+ }
2279
+ const { label } = CONNECTOR_TYPES[firewallRef];
2280
+ const action = opts.enable ? "enable" : "disable";
2281
+ const platformOrigin = await getPlatformOrigin();
2282
+ const agentId = process.env.ZERO_AGENT_ID;
2283
+ const urlParams = new URLSearchParams({
2284
+ ref: firewallRef,
2285
+ permission: opts.permission
2286
+ });
2287
+ const pagePath = agentId ? `/firewall-allow/${agentId}` : "/firewall-allow";
2288
+ const url = `${platformOrigin}${pagePath}?${urlParams.toString()}`;
2289
+ const role = agentId ? await resolveRole() : "unknown";
2290
+ if (role === "admin") {
2291
+ console.log(
2292
+ `You can ${action} the "${opts.permission}" permission directly: [Manage ${label} firewall](${url})`
2293
+ );
2294
+ } else if (role === "member") {
2295
+ if (action === "enable") {
2296
+ console.log(
2297
+ `Permission changes require admin approval. Request access at: [Request ${label} access](${url})`
2298
+ );
2299
+ } else {
2300
+ console.log(
2301
+ `Permission changes require admin approval. Contact an org admin to disable this permission: [View ${label} firewall](${url})`
2302
+ );
2303
+ }
2304
+ } else {
2305
+ console.log(
2306
+ `To ${action} the "${opts.permission}" permission on the ${label} firewall: [Manage ${label} firewall](${url})`
2307
+ );
2308
+ }
2185
2309
  }
2186
2310
  )
2187
2311
  );
2188
2312
 
2189
2313
  // src/commands/zero/doctor/index.ts
2190
- var zeroDoctorCommand = new Command37().name("doctor").description("Diagnose runtime issues (missing tokens, firewall denials)").addCommand(missingTokenCommand).addCommand(firewallDenyCommand).addHelpText(
2314
+ var zeroDoctorCommand = new Command38().name("doctor").description("Diagnose runtime issues (missing tokens, firewall denials)").addCommand(missingTokenCommand).addCommand(firewallDenyCommand).addCommand(firewallPermissionsChangeCommand).addHelpText(
2191
2315
  "after",
2192
2316
  `
2193
2317
  Examples:
2194
2318
  Missing an API key? zero doctor missing-token GITHUB_TOKEN
2195
2319
  Firewall blocked? zero doctor firewall-deny github --method GET --path /repos/owner/repo
2320
+ Change a permission? zero doctor firewall-permissions-change github --permission contents:read --enable
2196
2321
 
2197
2322
  Notes:
2198
2323
  - Use this when your task fails due to a missing environment variable or firewall denial
@@ -2200,7 +2325,7 @@ Notes:
2200
2325
  );
2201
2326
 
2202
2327
  // src/commands/zero/preference/index.ts
2203
- import { Command as Command38 } from "commander";
2328
+ import { Command as Command39 } from "commander";
2204
2329
  import chalk31 from "chalk";
2205
2330
  function detectTimezone2() {
2206
2331
  return Intl.DateTimeFormat().resolvedOptions().timeZone;
@@ -2257,7 +2382,7 @@ System timezone detected: ${detectedTz}`));
2257
2382
  }
2258
2383
  }
2259
2384
  }
2260
- var zeroPreferenceCommand = new Command38().name("preference").description("View or update user preferences (timezone, notifications)").option("--timezone <timezone>", "IANA timezone (e.g., America/New_York)").action(
2385
+ var zeroPreferenceCommand = new Command39().name("preference").description("View or update user preferences (timezone, notifications)").option("--timezone <timezone>", "IANA timezone (e.g., America/New_York)").action(
2261
2386
  withErrorHandler(async (opts) => {
2262
2387
  const updates = buildUpdates(opts);
2263
2388
  if (updates) {
@@ -2282,7 +2407,7 @@ var zeroPreferenceCommand = new Command38().name("preference").description("View
2282
2407
  );
2283
2408
 
2284
2409
  // src/commands/zero/run/run.ts
2285
- import { Command as Command39 } from "commander";
2410
+ import { Command as Command40 } from "commander";
2286
2411
 
2287
2412
  // src/commands/zero/run/shared.ts
2288
2413
  import chalk32 from "chalk";
@@ -2365,10 +2490,7 @@ function showZeroNextSteps(result) {
2365
2490
  }
2366
2491
 
2367
2492
  // src/commands/zero/run/run.ts
2368
- var mainRunCommand = new Command39().name("run").description("Delegate a task to a teammate agent").argument("<agent-id>", "Agent UUID (from `zero agent list`)").argument("<prompt>", "Task prompt for the agent").option(
2369
- "--append-system-prompt <text>",
2370
- "Append text to the agent's system prompt"
2371
- ).option(
2493
+ var mainRunCommand = new Command40().name("run").description("Delegate a task to a teammate agent").argument("<agent-id>", "Agent UUID (from `zero agent list`)").argument("<prompt>", "Task prompt for the agent").option(
2372
2494
  "--model-provider <type>",
2373
2495
  "Override model provider (e.g., anthropic-api-key)"
2374
2496
  ).option("--verbose", "Show full tool inputs and outputs").addHelpText(
@@ -2395,7 +2517,6 @@ Notes:
2395
2517
  const response = await createZeroRun({
2396
2518
  agentId,
2397
2519
  prompt,
2398
- appendSystemPrompt: options.appendSystemPrompt,
2399
2520
  modelProvider: options.modelProvider
2400
2521
  });
2401
2522
  if (response.status === "failed") {
@@ -2417,11 +2538,8 @@ Notes:
2417
2538
  );
2418
2539
 
2419
2540
  // src/commands/zero/run/continue.ts
2420
- import { Command as Command40 } from "commander";
2421
- var continueCommand = new Command40().name("continue").description("Continue a previous delegation from a session").argument("<session-id>", "Session ID from a previous run").argument("<prompt>", "Follow-up prompt for the agent").option(
2422
- "--append-system-prompt <text>",
2423
- "Append text to the agent's system prompt"
2424
- ).option(
2541
+ import { Command as Command41 } from "commander";
2542
+ var continueCommand = new Command41().name("continue").description("Continue a previous delegation from a session").argument("<session-id>", "Session ID from a previous run").argument("<prompt>", "Follow-up prompt for the agent").option(
2425
2543
  "--model-provider <type>",
2426
2544
  "Override model provider (e.g., anthropic-api-key)"
2427
2545
  ).option("--verbose", "Show full tool inputs and outputs").addHelpText(
@@ -2445,7 +2563,6 @@ Notes:
2445
2563
  const response = await createZeroRun({
2446
2564
  sessionId,
2447
2565
  prompt,
2448
- appendSystemPrompt: options.appendSystemPrompt,
2449
2566
  modelProvider: options.modelProvider
2450
2567
  });
2451
2568
  if (response.status === "failed") {
@@ -2479,10 +2596,10 @@ Examples:
2479
2596
  var zeroRunCommand = mainRunCommand;
2480
2597
 
2481
2598
  // src/commands/zero/schedule/index.ts
2482
- import { Command as Command47 } from "commander";
2599
+ import { Command as Command48 } from "commander";
2483
2600
 
2484
2601
  // src/commands/zero/schedule/setup.ts
2485
- import { Command as Command41 } from "commander";
2602
+ import { Command as Command42 } from "commander";
2486
2603
  import chalk33 from "chalk";
2487
2604
  var FREQUENCY_CHOICES = [
2488
2605
  { title: "Daily", value: "daily", description: "Run every day" },
@@ -2720,42 +2837,6 @@ async function gatherPromptText(optionPrompt, existingPrompt) {
2720
2837
  existingPrompt || "let's start working."
2721
2838
  );
2722
2839
  }
2723
- async function gatherNotificationPreferences(optionNotifyEmail, optionNotifySlack, optionNotifySlackChannelId, existingSchedule) {
2724
- if (optionNotifyEmail !== void 0 && optionNotifySlack !== void 0) {
2725
- return {
2726
- notifyEmail: optionNotifyEmail,
2727
- notifySlack: optionNotifySlack,
2728
- notifySlackChannelId: optionNotifySlackChannelId
2729
- };
2730
- }
2731
- if (!isInteractive()) {
2732
- return {
2733
- notifyEmail: optionNotifyEmail,
2734
- notifySlack: optionNotifySlack,
2735
- notifySlackChannelId: optionNotifySlackChannelId
2736
- };
2737
- }
2738
- const notifyEmail = optionNotifyEmail ?? await promptConfirm(
2739
- "Enable email notifications?",
2740
- existingSchedule?.notifyEmail ?? false
2741
- );
2742
- const notifySlack = optionNotifySlack ?? await promptConfirm(
2743
- "Enable Slack notifications?",
2744
- existingSchedule?.notifySlack ?? false
2745
- );
2746
- let notifySlackChannelId = optionNotifySlackChannelId;
2747
- if (notifySlackChannelId === void 0 && notifySlack) {
2748
- const defaultChannel = existingSchedule?.notifySlackChannelId ?? "";
2749
- const channelInput = await promptText(
2750
- "Slack channel ID (leave empty for DM)",
2751
- defaultChannel
2752
- );
2753
- if (channelInput) {
2754
- notifySlackChannelId = channelInput;
2755
- }
2756
- }
2757
- return { notifyEmail, notifySlack, notifySlackChannelId };
2758
- }
2759
2840
  async function gatherInterval(optionInterval, existingInterval) {
2760
2841
  if (optionInterval) {
2761
2842
  const val = parseInt(optionInterval, 10);
@@ -2848,16 +2929,7 @@ Deploying schedule for agent ${chalk33.cyan(params.agentName)}...`
2848
2929
  atTime: atTimeISO,
2849
2930
  intervalSeconds: params.intervalSeconds,
2850
2931
  timezone: params.timezone,
2851
- prompt: params.prompt,
2852
- ...params.notifyEmail !== void 0 && {
2853
- notifyEmail: params.notifyEmail
2854
- },
2855
- ...params.notifySlack !== void 0 && {
2856
- notifySlack: params.notifySlack
2857
- },
2858
- ...params.notifySlackChannelId !== void 0 && {
2859
- notifySlackChannelId: params.notifySlackChannelId
2860
- }
2932
+ prompt: params.prompt
2861
2933
  });
2862
2934
  return deployResult;
2863
2935
  }
@@ -2936,10 +3008,7 @@ async function handleScheduleEnabling(params) {
2936
3008
  showEnableHint(agentName);
2937
3009
  }
2938
3010
  }
2939
- var setupCommand2 = new Command41().name("setup").description("Create or edit a schedule for a zero agent").argument("<agent-id>", "Agent ID").option("-n, --name <schedule-name>", 'Schedule name (default: "default")').option("-f, --frequency <type>", "Frequency: daily|weekly|monthly|once|loop").option("-t, --time <HH:MM>", "Time to run (24-hour format)").option("-d, --day <day>", "Day of week (mon-sun) or day of month (1-31)").option("-i, --interval <seconds>", "Interval in seconds for loop mode").option("-z, --timezone <tz>", "IANA timezone").option("-p, --prompt <text>", "Prompt to run").option("-e, --enable", "Enable schedule immediately after creation").option("--notify-email", "Enable email notifications (default: false)").option("--no-notify-email", "Disable email notifications").option("--notify-slack", "Enable Slack notifications (default: false)").option("--no-notify-slack", "Disable Slack notifications").option(
2940
- "--notify-slack-channel-id <channel-id>",
2941
- "Slack channel ID for notifications (default: DM)"
2942
- ).addHelpText(
3011
+ var setupCommand2 = new Command42().name("setup").description("Create or edit a schedule for a zero agent").argument("<agent-id>", "Agent ID").option("-n, --name <schedule-name>", 'Schedule name (default: "default")').option("-f, --frequency <type>", "Frequency: daily|weekly|monthly|once|loop").option("-t, --time <HH:MM>", "Time to run (24-hour format)").option("-d, --day <day>", "Day of week (mon-sun) or day of month (1-31)").option("-i, --interval <seconds>", "Interval in seconds for loop mode").option("-z, --timezone <tz>", "IANA timezone").option("-p, --prompt <text>", "Prompt to run").option("-e, --enable", "Enable schedule immediately after creation").addHelpText(
2943
3012
  "after",
2944
3013
  `
2945
3014
  Examples:
@@ -2953,8 +3022,7 @@ Examples:
2953
3022
  Notes:
2954
3023
  - Re-running setup with the same agent updates the existing "default" schedule
2955
3024
  - Use -n to manage multiple named schedules for the same agent
2956
- - All flags are required in non-interactive mode; interactive mode prompts for missing values
2957
- - When --notify-slack is enabled, run results are automatically posted to the Slack channel specified by --notify-slack-channel-id (or as a DM if not set). No need to include Slack delivery instructions in your prompt.`
3025
+ - All flags are required in non-interactive mode; interactive mode prompts for missing values`
2958
3026
  ).action(
2959
3027
  withErrorHandler(async (agentIdentifier, options) => {
2960
3028
  const compose = await resolveCompose(agentIdentifier);
@@ -3004,12 +3072,6 @@ Notes:
3004
3072
  console.log(chalk33.dim("Cancelled"));
3005
3073
  return;
3006
3074
  }
3007
- const { notifyEmail, notifySlack, notifySlackChannelId } = await gatherNotificationPreferences(
3008
- options.notifyEmail,
3009
- options.notifySlack,
3010
- options.notifySlackChannelId,
3011
- existingSchedule
3012
- );
3013
3075
  const deployResult = await buildAndDeploy({
3014
3076
  scheduleName,
3015
3077
  agentId,
@@ -3020,10 +3082,7 @@ Notes:
3020
3082
  atTime,
3021
3083
  intervalSeconds,
3022
3084
  timezone,
3023
- prompt: promptText_,
3024
- notifyEmail,
3025
- notifySlack,
3026
- notifySlackChannelId
3085
+ prompt: promptText_
3027
3086
  });
3028
3087
  displayDeployResult(scheduleName, deployResult);
3029
3088
  const shouldPromptEnable = deployResult.created || existingSchedule !== void 0 && !existingSchedule.enabled;
@@ -3038,9 +3097,9 @@ Notes:
3038
3097
  );
3039
3098
 
3040
3099
  // src/commands/zero/schedule/list.ts
3041
- import { Command as Command42 } from "commander";
3100
+ import { Command as Command43 } from "commander";
3042
3101
  import chalk34 from "chalk";
3043
- var listCommand7 = new Command42().name("list").alias("ls").description("List all zero schedules").addHelpText(
3102
+ var listCommand7 = new Command43().name("list").alias("ls").description("List all zero schedules").addHelpText(
3044
3103
  "after",
3045
3104
  `
3046
3105
  Examples:
@@ -3098,7 +3157,7 @@ Examples:
3098
3157
  );
3099
3158
 
3100
3159
  // src/commands/zero/schedule/status.ts
3101
- import { Command as Command43 } from "commander";
3160
+ import { Command as Command44 } from "commander";
3102
3161
  import chalk35 from "chalk";
3103
3162
  function formatDateTimeStyled(dateStr) {
3104
3163
  if (!dateStr) return chalk35.dim("-");
@@ -3151,7 +3210,7 @@ function printTimeSchedule(schedule) {
3151
3210
  console.log(`${"Failures:".padEnd(16)}${failureText}`);
3152
3211
  }
3153
3212
  }
3154
- var statusCommand3 = new Command43().name("status").description("Show detailed status of a zero schedule").argument("<agent-id>", "Agent ID").option(
3213
+ var statusCommand3 = new Command44().name("status").description("Show detailed status of a zero schedule").argument("<agent-id>", "Agent ID").option(
3155
3214
  "-n, --name <schedule-name>",
3156
3215
  "Schedule name (required when agent has multiple schedules)"
3157
3216
  ).addHelpText(
@@ -3176,9 +3235,9 @@ Examples:
3176
3235
  );
3177
3236
 
3178
3237
  // src/commands/zero/schedule/delete.ts
3179
- import { Command as Command44 } from "commander";
3238
+ import { Command as Command45 } from "commander";
3180
3239
  import chalk36 from "chalk";
3181
- var deleteCommand3 = new Command44().name("delete").alias("rm").description("Delete a zero schedule").argument("<agent-id>", "Agent ID").option(
3240
+ var deleteCommand3 = new Command45().name("delete").alias("rm").description("Delete a zero schedule").argument("<agent-id>", "Agent ID").option(
3182
3241
  "-n, --name <schedule-name>",
3183
3242
  "Schedule name (required when agent has multiple schedules)"
3184
3243
  ).option("-y, --yes", "Skip confirmation prompt").addHelpText(
@@ -3220,9 +3279,9 @@ Notes:
3220
3279
  );
3221
3280
 
3222
3281
  // src/commands/zero/schedule/enable.ts
3223
- import { Command as Command45 } from "commander";
3282
+ import { Command as Command46 } from "commander";
3224
3283
  import chalk37 from "chalk";
3225
- var enableCommand = new Command45().name("enable").description("Enable a zero schedule").argument("<agent-id>", "Agent ID").option(
3284
+ var enableCommand = new Command46().name("enable").description("Enable a zero schedule").argument("<agent-id>", "Agent ID").option(
3226
3285
  "-n, --name <schedule-name>",
3227
3286
  "Schedule name (required when agent has multiple schedules)"
3228
3287
  ).addHelpText(
@@ -3246,9 +3305,9 @@ Examples:
3246
3305
  );
3247
3306
 
3248
3307
  // src/commands/zero/schedule/disable.ts
3249
- import { Command as Command46 } from "commander";
3308
+ import { Command as Command47 } from "commander";
3250
3309
  import chalk38 from "chalk";
3251
- var disableCommand = new Command46().name("disable").description("Disable a zero schedule").argument("<agent-id>", "Agent ID").option(
3310
+ var disableCommand = new Command47().name("disable").description("Disable a zero schedule").argument("<agent-id>", "Agent ID").option(
3252
3311
  "-n, --name <schedule-name>",
3253
3312
  "Schedule name (required when agent has multiple schedules)"
3254
3313
  ).addHelpText(
@@ -3272,7 +3331,7 @@ Examples:
3272
3331
  );
3273
3332
 
3274
3333
  // src/commands/zero/schedule/index.ts
3275
- var zeroScheduleCommand = new Command47().name("schedule").description("Create or manage recurring scheduled tasks").addCommand(setupCommand2).addCommand(listCommand7).addCommand(statusCommand3).addCommand(deleteCommand3).addCommand(enableCommand).addCommand(disableCommand).addHelpText(
3334
+ var zeroScheduleCommand = new Command48().name("schedule").description("Create or manage recurring scheduled tasks").addCommand(setupCommand2).addCommand(listCommand7).addCommand(statusCommand3).addCommand(deleteCommand3).addCommand(enableCommand).addCommand(disableCommand).addHelpText(
3276
3335
  "after",
3277
3336
  `
3278
3337
  Examples:
@@ -3285,12 +3344,12 @@ Examples:
3285
3344
  );
3286
3345
 
3287
3346
  // src/commands/zero/secret/index.ts
3288
- import { Command as Command51 } from "commander";
3347
+ import { Command as Command52 } from "commander";
3289
3348
 
3290
3349
  // src/commands/zero/secret/list.ts
3291
- import { Command as Command48 } from "commander";
3350
+ import { Command as Command49 } from "commander";
3292
3351
  import chalk39 from "chalk";
3293
- var listCommand8 = new Command48().name("list").alias("ls").description("List all secrets").action(
3352
+ var listCommand8 = new Command49().name("list").alias("ls").description("List all secrets").action(
3294
3353
  withErrorHandler(async () => {
3295
3354
  const result = await listZeroSecrets();
3296
3355
  if (result.secrets.length === 0) {
@@ -3343,9 +3402,9 @@ var listCommand8 = new Command48().name("list").alias("ls").description("List al
3343
3402
  );
3344
3403
 
3345
3404
  // src/commands/zero/secret/set.ts
3346
- import { Command as Command49 } from "commander";
3405
+ import { Command as Command50 } from "commander";
3347
3406
  import chalk40 from "chalk";
3348
- var setCommand4 = new Command49().name("set").description("Create or update a secret").argument("<name>", "Secret name (uppercase, e.g., MY_API_KEY)").option(
3407
+ var setCommand4 = new Command50().name("set").description("Create or update a secret").argument("<name>", "Secret name (uppercase, e.g., MY_API_KEY)").option(
3349
3408
  "-b, --body <value>",
3350
3409
  "Secret value (required in non-interactive mode)"
3351
3410
  ).option("-d, --description <description>", "Optional description").action(
@@ -3391,9 +3450,9 @@ var setCommand4 = new Command49().name("set").description("Create or update a se
3391
3450
  );
3392
3451
 
3393
3452
  // src/commands/zero/secret/delete.ts
3394
- import { Command as Command50 } from "commander";
3453
+ import { Command as Command51 } from "commander";
3395
3454
  import chalk41 from "chalk";
3396
- var deleteCommand4 = new Command50().name("delete").description("Delete a secret").argument("<name>", "Secret name to delete").option("-y, --yes", "Skip confirmation prompt").action(
3455
+ var deleteCommand4 = new Command51().name("delete").description("Delete a secret").argument("<name>", "Secret name to delete").option("-y, --yes", "Skip confirmation prompt").action(
3397
3456
  withErrorHandler(async (name, options) => {
3398
3457
  if (!options.yes) {
3399
3458
  if (!isInteractive()) {
@@ -3414,19 +3473,19 @@ var deleteCommand4 = new Command50().name("delete").description("Delete a secret
3414
3473
  );
3415
3474
 
3416
3475
  // src/commands/zero/secret/index.ts
3417
- var zeroSecretCommand = new Command51().name("secret").description("Read or write secrets (API keys, tokens)").addCommand(listCommand8).addCommand(setCommand4).addCommand(deleteCommand4);
3476
+ var zeroSecretCommand = new Command52().name("secret").description("Read or write secrets (API keys, tokens)").addCommand(listCommand8).addCommand(setCommand4).addCommand(deleteCommand4);
3418
3477
 
3419
3478
  // src/commands/zero/slack/index.ts
3420
- import { Command as Command54 } from "commander";
3479
+ import { Command as Command56 } from "commander";
3421
3480
 
3422
3481
  // src/commands/zero/slack/message/index.ts
3423
- import { Command as Command53 } from "commander";
3482
+ import { Command as Command54 } from "commander";
3424
3483
 
3425
3484
  // src/commands/zero/slack/message/send.ts
3426
3485
  import { readFileSync as readFileSync3 } from "fs";
3427
- import { Command as Command52 } from "commander";
3486
+ import { Command as Command53 } from "commander";
3428
3487
  import chalk42 from "chalk";
3429
- var sendCommand = new Command52().name("send").description("Send a message to a Slack channel").requiredOption("-c, --channel <id>", "Channel ID").option("-t, --text <message>", "Message text").option("--thread <ts>", "Thread timestamp for replies").option("--blocks <json>", "Block Kit JSON string").addHelpText(
3488
+ var sendCommand = new Command53().name("send").description("Send a message to a Slack channel").requiredOption("-c, --channel <id>", "Channel ID").option("-t, --text <message>", "Message text").option("--thread <ts>", "Thread timestamp for replies").option("--blocks <json>", "Block Kit JSON string").addHelpText(
3430
3489
  "after",
3431
3490
  `
3432
3491
  Examples:
@@ -3476,65 +3535,123 @@ Notes:
3476
3535
  );
3477
3536
 
3478
3537
  // src/commands/zero/slack/message/index.ts
3479
- var zeroSlackMessageCommand = new Command53().name("message").description("Manage Slack messages").addCommand(sendCommand).addHelpText(
3538
+ var zeroSlackMessageCommand = new Command54().name("message").description("Manage Slack messages").addCommand(sendCommand).addHelpText(
3480
3539
  "after",
3481
3540
  `
3482
3541
  Examples:
3483
3542
  zero slack message send -c <channel-id> -t "Hello!"`
3484
3543
  );
3485
3544
 
3545
+ // src/commands/zero/slack/upload-file.ts
3546
+ import { statSync, readFileSync as readFileSync4 } from "fs";
3547
+ import { basename } from "path";
3548
+ import { Command as Command55 } from "commander";
3549
+ import chalk43 from "chalk";
3550
+ var uploadFileCommand = new Command55().name("upload-file").description("Upload a file to a Slack channel as the bot").requiredOption("-f, --file <path>", "Local file path to upload").requiredOption("-c, --channel <id>", "Slack channel ID").option("--thread <ts>", "Thread timestamp to post as a reply").option("--title <title>", "Display title for the file").option("--comment <text>", "Initial comment to accompany the file").addHelpText(
3551
+ "after",
3552
+ `
3553
+ Examples:
3554
+ Upload a file: zero slack upload-file -f /tmp/report.pdf -c C01234
3555
+ Upload to thread: zero slack upload-file -f /tmp/log.txt -c C01234 --thread 1234567890.123456
3556
+ With title and comment: zero slack upload-file -f /tmp/data.csv -c C01234 --title "Daily Report" --comment "Here's the report"
3557
+
3558
+ Notes:
3559
+ - Uses the bot token (not user SLACK_TOKEN), so no files:write firewall permission is needed
3560
+ - Returns file_id and permalink for reference`
3561
+ ).action(
3562
+ withErrorHandler(
3563
+ async (options) => {
3564
+ let fileSize;
3565
+ try {
3566
+ const stat = statSync(options.file);
3567
+ fileSize = stat.size;
3568
+ } catch {
3569
+ throw new Error(`File not found: ${options.file}`);
3570
+ }
3571
+ if (fileSize === 0) {
3572
+ throw new Error("File is empty");
3573
+ }
3574
+ const filename = basename(options.file);
3575
+ const { uploadUrl, fileId } = await initSlackFileUpload({
3576
+ filename,
3577
+ length: fileSize
3578
+ });
3579
+ const fileContent = readFileSync4(options.file);
3580
+ const uploadResponse = await fetch(uploadUrl, {
3581
+ method: "POST",
3582
+ body: fileContent
3583
+ });
3584
+ if (!uploadResponse.ok) {
3585
+ throw new Error(
3586
+ `File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`
3587
+ );
3588
+ }
3589
+ const result = await completeSlackFileUpload({
3590
+ fileId,
3591
+ channel: options.channel,
3592
+ threadTs: options.thread,
3593
+ title: options.title,
3594
+ initialComment: options.comment
3595
+ });
3596
+ console.log(chalk43.green(`\u2713 File uploaded (file_id: ${result.fileId})`));
3597
+ console.log(chalk43.dim(` permalink: ${result.permalink}`));
3598
+ }
3599
+ )
3600
+ );
3601
+
3486
3602
  // src/commands/zero/slack/index.ts
3487
- var zeroSlackCommand = new Command54().name("slack").description("Send messages to Slack channels as the bot").addCommand(zeroSlackMessageCommand).addHelpText(
3603
+ var zeroSlackCommand = new Command56().name("slack").description("Send messages and upload files to Slack channels as the bot").addCommand(zeroSlackMessageCommand).addCommand(uploadFileCommand).addHelpText(
3488
3604
  "after",
3489
3605
  `
3490
3606
  Examples:
3491
3607
  Send a message: zero slack message send -c <channel-id> -t "Hello!"
3492
- Reply in a thread: zero slack message send -c <channel-id> --thread <ts> -t "reply"`
3608
+ Reply in a thread: zero slack message send -c <channel-id> --thread <ts> -t "reply"
3609
+ Upload a file: zero slack upload-file -f /tmp/report.pdf -c <channel-id>`
3493
3610
  );
3494
3611
 
3495
3612
  // src/commands/zero/variable/index.ts
3496
- import { Command as Command58 } from "commander";
3613
+ import { Command as Command60 } from "commander";
3497
3614
 
3498
3615
  // src/commands/zero/variable/list.ts
3499
- import { Command as Command55 } from "commander";
3500
- import chalk43 from "chalk";
3616
+ import { Command as Command57 } from "commander";
3617
+ import chalk44 from "chalk";
3501
3618
  function truncateValue2(value, maxLength = 60) {
3502
3619
  if (value.length <= maxLength) {
3503
3620
  return value;
3504
3621
  }
3505
3622
  return value.slice(0, maxLength - 15) + "... [truncated]";
3506
3623
  }
3507
- var listCommand9 = new Command55().name("list").alias("ls").description("List all variables").action(
3624
+ var listCommand9 = new Command57().name("list").alias("ls").description("List all variables").action(
3508
3625
  withErrorHandler(async () => {
3509
3626
  const result = await listZeroVariables();
3510
3627
  if (result.variables.length === 0) {
3511
- console.log(chalk43.dim("No variables found"));
3628
+ console.log(chalk44.dim("No variables found"));
3512
3629
  console.log();
3513
3630
  console.log("To add a variable:");
3514
- console.log(chalk43.cyan(" zero variable set MY_VAR <value>"));
3631
+ console.log(chalk44.cyan(" zero variable set MY_VAR <value>"));
3515
3632
  return;
3516
3633
  }
3517
- console.log(chalk43.bold("Variables:"));
3634
+ console.log(chalk44.bold("Variables:"));
3518
3635
  console.log();
3519
3636
  for (const variable of result.variables) {
3520
3637
  const displayValue = truncateValue2(variable.value);
3521
- console.log(` ${chalk43.cyan(variable.name)} = ${displayValue}`);
3638
+ console.log(` ${chalk44.cyan(variable.name)} = ${displayValue}`);
3522
3639
  if (variable.description) {
3523
- console.log(` ${chalk43.dim(variable.description)}`);
3640
+ console.log(` ${chalk44.dim(variable.description)}`);
3524
3641
  }
3525
3642
  console.log(
3526
- ` ${chalk43.dim(`Updated: ${new Date(variable.updatedAt).toLocaleString()}`)}`
3643
+ ` ${chalk44.dim(`Updated: ${new Date(variable.updatedAt).toLocaleString()}`)}`
3527
3644
  );
3528
3645
  console.log();
3529
3646
  }
3530
- console.log(chalk43.dim(`Total: ${result.variables.length} variable(s)`));
3647
+ console.log(chalk44.dim(`Total: ${result.variables.length} variable(s)`));
3531
3648
  })
3532
3649
  );
3533
3650
 
3534
3651
  // src/commands/zero/variable/set.ts
3535
- import { Command as Command56 } from "commander";
3536
- import chalk44 from "chalk";
3537
- var setCommand5 = new Command56().name("set").description("Create or update a variable").argument("<name>", "Variable name (uppercase, e.g., MY_VAR)").argument("<value>", "Variable value").option("-d, --description <description>", "Optional description").action(
3652
+ import { Command as Command58 } from "commander";
3653
+ import chalk45 from "chalk";
3654
+ var setCommand5 = new Command58().name("set").description("Create or update a variable").argument("<name>", "Variable name (uppercase, e.g., MY_VAR)").argument("<value>", "Variable value").option("-d, --description <description>", "Optional description").action(
3538
3655
  withErrorHandler(
3539
3656
  async (name, value, options) => {
3540
3657
  let variable;
@@ -3554,15 +3671,15 @@ var setCommand5 = new Command56().name("set").description("Create or update a va
3554
3671
  }
3555
3672
  throw error;
3556
3673
  }
3557
- console.log(chalk44.green(`\u2713 Variable "${variable.name}" saved`));
3674
+ console.log(chalk45.green(`\u2713 Variable "${variable.name}" saved`));
3558
3675
  }
3559
3676
  )
3560
3677
  );
3561
3678
 
3562
3679
  // src/commands/zero/variable/delete.ts
3563
- import { Command as Command57 } from "commander";
3564
- import chalk45 from "chalk";
3565
- var deleteCommand5 = new Command57().name("delete").description("Delete a variable").argument("<name>", "Variable name to delete").option("-y, --yes", "Skip confirmation prompt").action(
3680
+ import { Command as Command59 } from "commander";
3681
+ import chalk46 from "chalk";
3682
+ var deleteCommand5 = new Command59().name("delete").description("Delete a variable").argument("<name>", "Variable name to delete").option("-y, --yes", "Skip confirmation prompt").action(
3566
3683
  withErrorHandler(async (name, options) => {
3567
3684
  if (!options.yes) {
3568
3685
  if (!isInteractive()) {
@@ -3573,21 +3690,21 @@ var deleteCommand5 = new Command57().name("delete").description("Delete a variab
3573
3690
  false
3574
3691
  );
3575
3692
  if (!confirmed) {
3576
- console.log(chalk45.dim("Cancelled"));
3693
+ console.log(chalk46.dim("Cancelled"));
3577
3694
  return;
3578
3695
  }
3579
3696
  }
3580
3697
  await deleteZeroVariable(name);
3581
- console.log(chalk45.green(`\u2713 Variable "${name}" deleted`));
3698
+ console.log(chalk46.green(`\u2713 Variable "${name}" deleted`));
3582
3699
  })
3583
3700
  );
3584
3701
 
3585
3702
  // src/commands/zero/variable/index.ts
3586
- var zeroVariableCommand = new Command58().name("variable").description("Read or write non-sensitive configuration values").addCommand(listCommand9).addCommand(setCommand5).addCommand(deleteCommand5);
3703
+ var zeroVariableCommand = new Command60().name("variable").description("Read or write non-sensitive configuration values").addCommand(listCommand9).addCommand(setCommand5).addCommand(deleteCommand5);
3587
3704
 
3588
3705
  // src/commands/zero/whoami.ts
3589
- import { Command as Command59 } from "commander";
3590
- import chalk46 from "chalk";
3706
+ import { Command as Command61 } from "commander";
3707
+ import chalk47 from "chalk";
3591
3708
  function isInsideSandbox() {
3592
3709
  return !!process.env.ZERO_AGENT_ID;
3593
3710
  }
@@ -3595,11 +3712,11 @@ async function showSandboxInfo() {
3595
3712
  const agentId = process.env.ZERO_AGENT_ID;
3596
3713
  const payload = decodeZeroTokenPayload();
3597
3714
  console.log(`Agent ID: ${agentId}`);
3598
- console.log(`Run ID: ${payload?.runId ?? chalk46.dim("unavailable")}`);
3599
- console.log(`Org ID: ${payload?.orgId ?? chalk46.dim("unavailable")}`);
3715
+ console.log(`Run ID: ${payload?.runId ?? chalk47.dim("unavailable")}`);
3716
+ console.log(`Org ID: ${payload?.orgId ?? chalk47.dim("unavailable")}`);
3600
3717
  if (payload?.capabilities?.length) {
3601
3718
  console.log();
3602
- console.log(chalk46.bold("Capabilities:"));
3719
+ console.log(chalk47.bold("Capabilities:"));
3603
3720
  console.log(` ${payload.capabilities.join(", ")}`);
3604
3721
  }
3605
3722
  }
@@ -3607,23 +3724,23 @@ async function showLocalInfo() {
3607
3724
  const token = await getToken();
3608
3725
  const apiUrl = await getApiUrl();
3609
3726
  const activeOrg = await getActiveOrg();
3610
- console.log(chalk46.bold("Auth:"));
3727
+ console.log(chalk47.bold("Auth:"));
3611
3728
  if (token) {
3612
3729
  const tokenSource = process.env.ZERO_TOKEN ? "ZERO_TOKEN env var" : process.env.VM0_TOKEN ? "VM0_TOKEN env var" : "config file";
3613
3730
  console.log(
3614
- ` Status: ${chalk46.green("Authenticated")} (via ${tokenSource})`
3731
+ ` Status: ${chalk47.green("Authenticated")} (via ${tokenSource})`
3615
3732
  );
3616
3733
  } else {
3617
- console.log(` Status: ${chalk46.dim("Not authenticated")}`);
3734
+ console.log(` Status: ${chalk47.dim("Not authenticated")}`);
3618
3735
  }
3619
3736
  console.log(` API: ${apiUrl}`);
3620
3737
  console.log();
3621
3738
  if (activeOrg) {
3622
- console.log(chalk46.bold("Org:"));
3739
+ console.log(chalk47.bold("Org:"));
3623
3740
  console.log(` Active: ${activeOrg}`);
3624
3741
  }
3625
3742
  }
3626
- var zeroWhoamiCommand = new Command59().name("whoami").description("Show agent identity, run ID, and capabilities").addHelpText(
3743
+ var zeroWhoamiCommand = new Command61().name("whoami").description("Show agent identity, run ID, and capabilities").addHelpText(
3627
3744
  "after",
3628
3745
  `
3629
3746
  Examples:
@@ -3643,11 +3760,11 @@ Notes:
3643
3760
  );
3644
3761
 
3645
3762
  // src/commands/zero/ask-user/index.ts
3646
- import { Command as Command61 } from "commander";
3763
+ import { Command as Command63 } from "commander";
3647
3764
 
3648
3765
  // src/commands/zero/ask-user/question.ts
3649
- import { Command as Command60 } from "commander";
3650
- import chalk47 from "chalk";
3766
+ import { Command as Command62 } from "commander";
3767
+ import chalk48 from "chalk";
3651
3768
  function collectOption(value, previous) {
3652
3769
  const list = previous ?? [];
3653
3770
  list.push({ label: value });
@@ -3658,7 +3775,7 @@ function collectDesc(value, previous) {
3658
3775
  list.push(value);
3659
3776
  return list;
3660
3777
  }
3661
- var questionCommand = new Command60().name("question").description("Ask the user a question and wait for the answer").argument("<question>", "The question to ask").option("--header <text>", "Short label displayed as chip/tag (max 12 chars)").option("--option <label>", "Add a choice option (repeatable)", collectOption).option(
3778
+ var questionCommand = new Command62().name("question").description("Ask the user a question and wait for the answer").argument("<question>", "The question to ask").option("--header <text>", "Short label displayed as chip/tag (max 12 chars)").option("--option <label>", "Add a choice option (repeatable)", collectOption).option(
3662
3779
  "--desc <text>",
3663
3780
  "Description for the preceding --option",
3664
3781
  collectDesc
@@ -3714,7 +3831,7 @@ Notes:
3714
3831
  questions: [questionItem]
3715
3832
  });
3716
3833
  console.error(
3717
- chalk47.dim(
3834
+ chalk48.dim(
3718
3835
  `\u23F3 Waiting for user response... (pendingId: ${pendingId})`
3719
3836
  )
3720
3837
  );
@@ -3741,7 +3858,7 @@ Notes:
3741
3858
  );
3742
3859
 
3743
3860
  // src/commands/zero/ask-user/index.ts
3744
- var zeroAskUserCommand = new Command61().name("ask-user").description("Ask the user a question and wait for the answer").addCommand(questionCommand).addHelpText(
3861
+ var zeroAskUserCommand = new Command63().name("ask-user").description("Ask the user a question and wait for the answer").addCommand(questionCommand).addHelpText(
3745
3862
  "after",
3746
3863
  `
3747
3864
  Examples:
@@ -3753,14 +3870,44 @@ Notes:
3753
3870
  );
3754
3871
 
3755
3872
  // src/commands/zero/skill/index.ts
3756
- import { Command as Command67 } from "commander";
3873
+ import { Command as Command69 } from "commander";
3757
3874
 
3758
3875
  // src/commands/zero/skill/create.ts
3759
- import { Command as Command62 } from "commander";
3760
- import { readFileSync as readFileSync4, existsSync } from "fs";
3876
+ import { Command as Command64 } from "commander";
3877
+ import chalk49 from "chalk";
3878
+
3879
+ // src/lib/skill-directory.ts
3880
+ import { readFileSync as readFileSync5, readdirSync } from "fs";
3761
3881
  import { join as join2 } from "path";
3762
- import chalk48 from "chalk";
3763
- var createCommand2 = new Command62().name("create").description("Create a custom skill in the organization").argument("<name>", "Skill name (lowercase alphanumeric with hyphens)").requiredOption("--dir <path>", "Path to directory containing SKILL.md").option("--display-name <name>", "Skill display name").option("--description <text>", "Skill description").addHelpText(
3882
+ var IGNORED_NAMES = /* @__PURE__ */ new Set(["node_modules", ".git", ".DS_Store"]);
3883
+ function readSkillDirectory(dirPath) {
3884
+ const files = [];
3885
+ function walk(dir, prefix) {
3886
+ const entries = readdirSync(dir, { withFileTypes: true });
3887
+ for (const entry of entries) {
3888
+ if (entry.name.startsWith(".") || IGNORED_NAMES.has(entry.name)) continue;
3889
+ const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
3890
+ if (entry.isDirectory()) {
3891
+ walk(join2(dir, entry.name), relPath);
3892
+ } else {
3893
+ files.push({
3894
+ path: relPath,
3895
+ content: readFileSync5(join2(dir, entry.name), "utf-8")
3896
+ });
3897
+ }
3898
+ }
3899
+ }
3900
+ walk(dirPath, "");
3901
+ if (!files.some((f) => {
3902
+ return f.path === "SKILL.md";
3903
+ })) {
3904
+ throw new Error(`SKILL.md not found in ${dirPath}`);
3905
+ }
3906
+ return files;
3907
+ }
3908
+
3909
+ // src/commands/zero/skill/create.ts
3910
+ var createCommand2 = new Command64().name("create").description("Create a custom skill in the organization").argument("<name>", "Skill name (lowercase alphanumeric with hyphens)").requiredOption("--dir <path>", "Path to directory containing SKILL.md").option("--display-name <name>", "Skill display name").option("--description <text>", "Skill description").addHelpText(
3764
3911
  "after",
3765
3912
  `
3766
3913
  Examples:
@@ -3769,24 +3916,22 @@ Examples:
3769
3916
 
3770
3917
  Notes:
3771
3918
  - The directory must contain a SKILL.md file
3919
+ - All files in the directory are uploaded (hidden files and node_modules excluded)
3772
3920
  - The skill is created in the organization but not bound to any agent
3773
3921
  - Use 'zero agent edit <id> --add-skill <name>' to bind a skill to an agent`
3774
3922
  ).action(
3775
3923
  withErrorHandler(
3776
3924
  async (name, options) => {
3777
- const skillMdPath = join2(options.dir, "SKILL.md");
3778
- if (!existsSync(skillMdPath)) {
3779
- throw new Error(`SKILL.md not found in ${options.dir}`);
3780
- }
3781
- const content = readFileSync4(skillMdPath, "utf-8");
3925
+ const files = readSkillDirectory(options.dir);
3782
3926
  const skill = await createSkill({
3783
3927
  name,
3784
- content,
3928
+ files,
3785
3929
  displayName: options.displayName,
3786
3930
  description: options.description
3787
3931
  });
3788
- console.log(chalk48.green(`\u2713 Skill "${skill.name}" created`));
3932
+ console.log(chalk49.green(`\u2713 Skill "${skill.name}" created`));
3789
3933
  console.log(` Name: ${skill.name}`);
3934
+ console.log(` Files: ${files.length} file(s)`);
3790
3935
  if (skill.displayName) {
3791
3936
  console.log(` Display Name: ${skill.displayName}`);
3792
3937
  }
@@ -3798,13 +3943,11 @@ Notes:
3798
3943
  );
3799
3944
 
3800
3945
  // src/commands/zero/skill/edit.ts
3801
- import { Command as Command63 } from "commander";
3802
- import { readFileSync as readFileSync5, existsSync as existsSync2 } from "fs";
3803
- import { join as join3 } from "path";
3804
- import chalk49 from "chalk";
3805
- var editCommand2 = new Command63().name("edit").description("Update a custom skill's content").argument("<name>", "Skill name").requiredOption(
3946
+ import { Command as Command65 } from "commander";
3947
+ import chalk50 from "chalk";
3948
+ var editCommand2 = new Command65().name("edit").description("Update a custom skill's content").argument("<name>", "Skill name").requiredOption(
3806
3949
  "--dir <path>",
3807
- "Path to directory containing updated SKILL.md"
3950
+ "Path to directory containing updated skill files"
3808
3951
  ).addHelpText(
3809
3952
  "after",
3810
3953
  `
@@ -3812,20 +3955,18 @@ Examples:
3812
3955
  zero skill edit my-skill --dir ./skills/my-skill/`
3813
3956
  ).action(
3814
3957
  withErrorHandler(async (name, options) => {
3815
- const skillMdPath = join3(options.dir, "SKILL.md");
3816
- if (!existsSync2(skillMdPath)) {
3817
- throw new Error(`SKILL.md not found in ${options.dir}`);
3818
- }
3819
- const content = readFileSync5(skillMdPath, "utf-8");
3820
- await updateSkill(name, { content });
3821
- console.log(chalk49.green(`\u2713 Skill "${name}" updated`));
3958
+ const files = readSkillDirectory(options.dir);
3959
+ await updateSkill(name, { files });
3960
+ console.log(
3961
+ chalk50.green(`\u2713 Skill "${name}" updated (${files.length} file(s))`)
3962
+ );
3822
3963
  })
3823
3964
  );
3824
3965
 
3825
3966
  // src/commands/zero/skill/view.ts
3826
- import { Command as Command64 } from "commander";
3827
- import chalk50 from "chalk";
3828
- var viewCommand2 = new Command64().name("view").description("View a custom skill").argument("<name>", "Skill name").addHelpText(
3967
+ import { Command as Command66 } from "commander";
3968
+ import chalk51 from "chalk";
3969
+ var viewCommand2 = new Command66().name("view").description("View a custom skill").argument("<name>", "Skill name").addHelpText(
3829
3970
  "after",
3830
3971
  `
3831
3972
  Examples:
@@ -3833,26 +3974,33 @@ Examples:
3833
3974
  ).action(
3834
3975
  withErrorHandler(async (name) => {
3835
3976
  const skill = await getSkill(name);
3836
- console.log(chalk50.bold(skill.name));
3837
- if (skill.displayName) console.log(chalk50.dim(skill.displayName));
3977
+ console.log(chalk51.bold(skill.name));
3978
+ if (skill.displayName) console.log(chalk51.dim(skill.displayName));
3838
3979
  console.log();
3839
3980
  console.log(`Name: ${skill.name}`);
3840
3981
  if (skill.displayName) console.log(`Display Name: ${skill.displayName}`);
3841
3982
  if (skill.description) console.log(`Description: ${skill.description}`);
3983
+ if (skill.files && skill.files.length > 0) {
3984
+ console.log();
3985
+ console.log(chalk51.dim("\u2500\u2500 Files \u2500\u2500"));
3986
+ for (const f of skill.files) {
3987
+ console.log(` ${f.path} (${f.size} bytes)`);
3988
+ }
3989
+ }
3842
3990
  console.log();
3843
3991
  if (skill.content) {
3844
- console.log(chalk50.dim("\u2500\u2500 SKILL.md \u2500\u2500"));
3992
+ console.log(chalk51.dim("\u2500\u2500 SKILL.md \u2500\u2500"));
3845
3993
  console.log(skill.content);
3846
3994
  } else {
3847
- console.log(chalk50.dim("No content"));
3995
+ console.log(chalk51.dim("No content"));
3848
3996
  }
3849
3997
  })
3850
3998
  );
3851
3999
 
3852
4000
  // src/commands/zero/skill/list.ts
3853
- import { Command as Command65 } from "commander";
3854
- import chalk51 from "chalk";
3855
- var listCommand10 = new Command65().name("list").alias("ls").description("List custom skills in the organization").addHelpText(
4001
+ import { Command as Command67 } from "commander";
4002
+ import chalk52 from "chalk";
4003
+ var listCommand10 = new Command67().name("list").alias("ls").description("List custom skills in the organization").addHelpText(
3856
4004
  "after",
3857
4005
  `
3858
4006
  Examples:
@@ -3861,9 +4009,9 @@ Examples:
3861
4009
  withErrorHandler(async () => {
3862
4010
  const skills = await listSkills();
3863
4011
  if (skills.length === 0) {
3864
- console.log(chalk51.dim("No custom skills found"));
4012
+ console.log(chalk52.dim("No custom skills found"));
3865
4013
  console.log(
3866
- chalk51.dim(" Create one with: zero skill create <name> --dir <path>")
4014
+ chalk52.dim(" Create one with: zero skill create <name> --dir <path>")
3867
4015
  );
3868
4016
  return;
3869
4017
  }
@@ -3884,7 +4032,7 @@ Examples:
3884
4032
  "DISPLAY NAME".padEnd(displayWidth),
3885
4033
  "DESCRIPTION"
3886
4034
  ].join(" ");
3887
- console.log(chalk51.dim(header));
4035
+ console.log(chalk52.dim(header));
3888
4036
  for (const skill of skills) {
3889
4037
  const row = [
3890
4038
  skill.name.padEnd(nameWidth),
@@ -3897,9 +4045,9 @@ Examples:
3897
4045
  );
3898
4046
 
3899
4047
  // src/commands/zero/skill/delete.ts
3900
- import { Command as Command66 } from "commander";
3901
- import chalk52 from "chalk";
3902
- var deleteCommand6 = new Command66().name("delete").alias("rm").description("Delete a custom skill from the organization").argument("<name>", "Skill name").option("-y, --yes", "Skip confirmation prompt").addHelpText(
4048
+ import { Command as Command68 } from "commander";
4049
+ import chalk53 from "chalk";
4050
+ var deleteCommand6 = new Command68().name("delete").alias("rm").description("Delete a custom skill from the organization").argument("<name>", "Skill name").option("-y, --yes", "Skip confirmation prompt").addHelpText(
3903
4051
  "after",
3904
4052
  `
3905
4053
  Examples:
@@ -3921,17 +4069,17 @@ Notes:
3921
4069
  false
3922
4070
  );
3923
4071
  if (!confirmed) {
3924
- console.log(chalk52.dim("Cancelled"));
4072
+ console.log(chalk53.dim("Cancelled"));
3925
4073
  return;
3926
4074
  }
3927
4075
  }
3928
4076
  await deleteSkill(name);
3929
- console.log(chalk52.green(`\u2713 Skill "${name}" deleted`));
4077
+ console.log(chalk53.green(`\u2713 Skill "${name}" deleted`));
3930
4078
  })
3931
4079
  );
3932
4080
 
3933
4081
  // src/commands/zero/skill/index.ts
3934
- var zeroSkillCommand = new Command67("skill").description("Manage custom skills").addCommand(createCommand2).addCommand(editCommand2).addCommand(viewCommand2).addCommand(listCommand10).addCommand(deleteCommand6).addHelpText(
4082
+ var zeroSkillCommand = new Command69("skill").description("Manage custom skills").addCommand(createCommand2).addCommand(editCommand2).addCommand(viewCommand2).addCommand(listCommand10).addCommand(deleteCommand6).addHelpText(
3935
4083
  "after",
3936
4084
  `
3937
4085
  Examples:
@@ -3987,10 +4135,10 @@ function registerZeroCommands(prog, commands) {
3987
4135
  prog.addCommand(cmd, hidden ? { hidden: true } : {});
3988
4136
  }
3989
4137
  }
3990
- var program = new Command68();
4138
+ var program = new Command70();
3991
4139
  program.name("zero").description(
3992
4140
  "Zero CLI \u2014 interact with the zero platform from inside the sandbox"
3993
- ).version("9.92.1").addHelpText(
4141
+ ).version("9.94.0").addHelpText(
3994
4142
  "after",
3995
4143
  `
3996
4144
  Examples: