buckyos 0.7.131 → 0.7.133

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/cli/dist/cli.mjs CHANGED
@@ -575,6 +575,7 @@ function collectArgumentPaths(argv) {
575
575
  "name"
576
576
  ]);
577
577
  const booleanOptions = /* @__PURE__ */ new Set([
578
+ "replace",
578
579
  "cli",
579
580
  "wait",
580
581
  "non-interactive",
@@ -621,6 +622,8 @@ function collectArgumentPaths(argv) {
621
622
  write.push(value);
622
623
  } else if (name === "path")
623
624
  write.push(value);
625
+ else if (name === "app-doc" && module === "app" && verb === "publish")
626
+ read.push(value);
624
627
  else if (name === "file" && module === "system-config" && verb === "set-file") {
625
628
  read.push(value);
626
629
  } else if (name === "root" && module === "provision") {
@@ -638,6 +641,8 @@ function collectArgumentPaths(argv) {
638
641
  if (module === "app" && ["fetch", "install"].includes(verb ?? "") && positional++ === 0) {
639
642
  if (!/^https?:\/\//i.test(token))
640
643
  read.push(token);
644
+ } else if (module === "skill" && verb === "install" && positional++ === 0) {
645
+ read.push(token);
641
646
  } else if (module === "pikg" && positional++ === 0) {
642
647
  read.push(token);
643
648
  if (verb === "init" || verb === "pack")
@@ -681,9 +686,9 @@ async function readDistributionManifest(host2 = getHost()) {
681
686
  function distributionManifestView(manifest) {
682
687
  if (!manifest)
683
688
  return null;
684
- const { npm_files: files, ...summary } = manifest;
689
+ const { npm_files: files, ...summary2 } = manifest;
685
690
  return {
686
- ...summary,
691
+ ...summary2,
687
692
  npm_file_count: Array.isArray(files) ? files.length : null
688
693
  };
689
694
  }
@@ -2493,8 +2498,8 @@ function replPrompt(config) {
2493
2498
  const identity = config.identity ?? "external-session";
2494
2499
  return `buckyos[${profile}|${zone}|${identity}]> `;
2495
2500
  }
2496
- const EMPTY_INPUT$1 = { type: "object", properties: {}, additionalProperties: false };
2497
- const OBJECT_OUTPUT$8 = { type: "object", additionalProperties: true };
2501
+ const EMPTY_INPUT$3 = { type: "object", properties: {}, additionalProperties: false };
2502
+ const OBJECT_OUTPUT$c = { type: "object", additionalProperties: true };
2498
2503
  function createAuthModule() {
2499
2504
  return {
2500
2505
  name: "auth",
@@ -2503,8 +2508,8 @@ function createAuthModule() {
2503
2508
  {
2504
2509
  verb: "whoami",
2505
2510
  summary: "Show the effective principal and application identity",
2506
- inputSchema: EMPTY_INPUT$1,
2507
- outputSchema: OBJECT_OUTPUT$8,
2511
+ inputSchema: EMPTY_INPUT$3,
2512
+ outputSchema: OBJECT_OUTPUT$c,
2508
2513
  resultSchemaVersion: 1,
2509
2514
  access: { mode: "fixed", level: "read" },
2510
2515
  asyncMode: "sync",
@@ -2521,8 +2526,8 @@ function createAuthModule() {
2521
2526
  {
2522
2527
  verb: "session-status",
2523
2528
  summary: "Show the in-memory session state without exposing credentials",
2524
- inputSchema: EMPTY_INPUT$1,
2525
- outputSchema: OBJECT_OUTPUT$8,
2529
+ inputSchema: EMPTY_INPUT$3,
2530
+ outputSchema: OBJECT_OUTPUT$c,
2526
2531
  resultSchemaVersion: 1,
2527
2532
  access: { mode: "fixed", level: "read" },
2528
2533
  asyncMode: "sync",
@@ -2538,12 +2543,12 @@ function createAuthModule() {
2538
2543
  ]
2539
2544
  };
2540
2545
  }
2541
- const EMPTY_INPUT = {
2546
+ const EMPTY_INPUT$2 = {
2542
2547
  type: "object",
2543
2548
  properties: {},
2544
2549
  additionalProperties: false
2545
2550
  };
2546
- const OBJECT_OUTPUT$7 = { type: "object", additionalProperties: true };
2551
+ const OBJECT_OUTPUT$b = { type: "object", additionalProperties: true };
2547
2552
  function createCoreModules(registry) {
2548
2553
  return [createCommandModule(registry), createConfigModule(), createCompletionModule(registry)];
2549
2554
  }
@@ -2555,8 +2560,8 @@ function createCommandModule(registry) {
2555
2560
  {
2556
2561
  verb: "list",
2557
2562
  summary: "List registered modules and commands",
2558
- inputSchema: EMPTY_INPUT,
2559
- outputSchema: OBJECT_OUTPUT$7,
2563
+ inputSchema: EMPTY_INPUT$2,
2564
+ outputSchema: OBJECT_OUTPUT$b,
2560
2565
  resultSchemaVersion: 1,
2561
2566
  access: { mode: "fixed", level: "read" },
2562
2567
  asyncMode: "sync",
@@ -2589,7 +2594,7 @@ function createCommandModule(registry) {
2589
2594
  required: ["target_module", "target_verb"],
2590
2595
  additionalProperties: false
2591
2596
  },
2592
- outputSchema: OBJECT_OUTPUT$7,
2597
+ outputSchema: OBJECT_OUTPUT$b,
2593
2598
  resultSchemaVersion: 1,
2594
2599
  access: { mode: "fixed", level: "read" },
2595
2600
  asyncMode: "sync",
@@ -2610,8 +2615,8 @@ function createConfigModule() {
2610
2615
  {
2611
2616
  verb: "list",
2612
2617
  summary: "List the global configuration and available profiles",
2613
- inputSchema: EMPTY_INPUT,
2614
- outputSchema: OBJECT_OUTPUT$7,
2618
+ inputSchema: EMPTY_INPUT$2,
2619
+ outputSchema: OBJECT_OUTPUT$b,
2615
2620
  resultSchemaVersion: 1,
2616
2621
  access: { mode: "fixed", level: "read" },
2617
2622
  asyncMode: "sync",
@@ -2642,7 +2647,7 @@ function createConfigModule() {
2642
2647
  },
2643
2648
  additionalProperties: false
2644
2649
  },
2645
- outputSchema: OBJECT_OUTPUT$7,
2650
+ outputSchema: OBJECT_OUTPUT$b,
2646
2651
  resultSchemaVersion: 1,
2647
2652
  access: { mode: "fixed", level: "read" },
2648
2653
  asyncMode: "sync",
@@ -2688,7 +2693,7 @@ function createConfigModule() {
2688
2693
  required: ["key", "value"],
2689
2694
  additionalProperties: false
2690
2695
  },
2691
- outputSchema: OBJECT_OUTPUT$7,
2696
+ outputSchema: OBJECT_OUTPUT$b,
2692
2697
  resultSchemaVersion: 1,
2693
2698
  access: { mode: "fixed", level: "write" },
2694
2699
  asyncMode: "sync",
@@ -2728,7 +2733,7 @@ function createConfigModule() {
2728
2733
  required: ["profile_name"],
2729
2734
  additionalProperties: false
2730
2735
  },
2731
- outputSchema: OBJECT_OUTPUT$7,
2736
+ outputSchema: OBJECT_OUTPUT$b,
2732
2737
  resultSchemaVersion: 1,
2733
2738
  access: { mode: "fixed", level: "write" },
2734
2739
  asyncMode: "sync",
@@ -2760,7 +2765,7 @@ function createConfigModule() {
2760
2765
  properties: { effective: { type: "boolean" } },
2761
2766
  additionalProperties: false
2762
2767
  },
2763
- outputSchema: OBJECT_OUTPUT$7,
2768
+ outputSchema: OBJECT_OUTPUT$b,
2764
2769
  resultSchemaVersion: 1,
2765
2770
  access: { mode: "fixed", level: "read" },
2766
2771
  asyncMode: "sync",
@@ -2875,6 +2880,81 @@ complete -F _buckyos_complete buckyos
2875
2880
  # ${commands}
2876
2881
  `;
2877
2882
  }
2883
+ function rpcOptions$2(ctx) {
2884
+ return {
2885
+ traceId: ctx.traceId,
2886
+ timeoutMs: Math.max(1, (ctx.deadline ?? Date.now()) - Date.now()),
2887
+ signal: ctx.signal
2888
+ };
2889
+ }
2890
+ async function callService(ctx, service, method, params) {
2891
+ try {
2892
+ return await ctx.clients.call(service, method, params, rpcOptions$2(ctx));
2893
+ } catch (error) {
2894
+ const message = error instanceof Error ? error.message : String(error);
2895
+ const stable = message.match(/\b((?:TASK|AUDIT|DIAGNOSTIC|LOG)_[A-Z0-9_]+):/);
2896
+ if (stable)
2897
+ throw new ToolError(stable[1], message);
2898
+ throw error;
2899
+ }
2900
+ }
2901
+ function expectObject$4(value, label) {
2902
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2903
+ throw new ToolError("INVALID_SERVICE_RESPONSE", `${label} must be an object`, EXIT_INTERNAL);
2904
+ }
2905
+ return value;
2906
+ }
2907
+ function expectString$2(value, label) {
2908
+ if (typeof value !== "string" || !value.trim()) {
2909
+ throw new ToolError("INVALID_SERVICE_RESPONSE", `${label} must be a string`, EXIT_INTERNAL);
2910
+ }
2911
+ return value;
2912
+ }
2913
+ function inputString(input, key) {
2914
+ const value = input[key];
2915
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2916
+ }
2917
+ function requiredInputString(input, key) {
2918
+ const value = inputString(input, key);
2919
+ if (!value)
2920
+ throw new UsageError("INVALID_ARGUMENT", `${key} is required`);
2921
+ return value;
2922
+ }
2923
+ function parseTimestamp(value, key) {
2924
+ if (value === void 0)
2925
+ return void 0;
2926
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0)
2927
+ return value;
2928
+ if (typeof value !== "string" || !value.trim()) {
2929
+ throw new UsageError("INVALID_ARGUMENT", `${key} must be RFC 3339 or Unix milliseconds`);
2930
+ }
2931
+ if (/^\d+$/.test(value)) {
2932
+ const milliseconds2 = Number(value);
2933
+ if (Number.isSafeInteger(milliseconds2))
2934
+ return milliseconds2;
2935
+ }
2936
+ const milliseconds = Date.parse(value);
2937
+ if (!Number.isFinite(milliseconds)) {
2938
+ throw new UsageError("INVALID_ARGUMENT", `${key} must be RFC 3339 or Unix milliseconds`);
2939
+ }
2940
+ return milliseconds;
2941
+ }
2942
+ function splitServices(value) {
2943
+ const items = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
2944
+ return [...new Set(items.map((item) => String(item).trim()).filter(Boolean))];
2945
+ }
2946
+ const CONTROL_PANEL$4 = "control-panel";
2947
+ const EMPTY_INPUT$1 = { type: "object", properties: {}, additionalProperties: false };
2948
+ const BUCKYOS_INFO = {
2949
+ type: "object",
2950
+ properties: {
2951
+ version: { type: "string" },
2952
+ build_version: { type: "string" },
2953
+ release_channel: { type: "string" },
2954
+ target: { type: "string" }
2955
+ },
2956
+ additionalProperties: true
2957
+ };
2878
2958
  function createSystemModule() {
2879
2959
  return {
2880
2960
  name: "system",
@@ -2882,30 +2962,52 @@ function createSystemModule() {
2882
2962
  commands: [
2883
2963
  {
2884
2964
  verb: "status",
2885
- summary: "Get the Zone overview, health, services, and version",
2886
- inputSchema: { type: "object", properties: {}, additionalProperties: false },
2887
- outputSchema: { type: "object", additionalProperties: true },
2965
+ summary: "Get host resource state, configured service keys, and the BuckyOS version",
2966
+ description: "state and warnings come from CPU/memory/disk/swap of the Control Panel host; services lists the keys under services/ with status unknown (not a per-service health check); buckyos is the system.buckyos_info.get record.",
2967
+ inputSchema: EMPTY_INPUT$1,
2968
+ outputSchema: {
2969
+ type: "object",
2970
+ properties: { buckyos: BUCKYOS_INFO },
2971
+ required: ["buckyos"],
2972
+ additionalProperties: true
2973
+ },
2888
2974
  resultSchemaVersion: 1,
2889
2975
  access: { mode: "fixed", level: "read" },
2890
2976
  asyncMode: "sync",
2891
2977
  requiresSession: true,
2892
2978
  examples: ["buckyos --profile production system status"],
2893
- handler: async (ctx) => await ctx.clients.call(
2894
- "control-panel",
2895
- "system.status",
2896
- {},
2897
- {
2898
- traceId: ctx.traceId,
2899
- timeoutMs: Math.max(1, (ctx.deadline ?? Date.now()) - Date.now()),
2900
- signal: ctx.signal
2901
- }
2902
- )
2979
+ handler: async (ctx) => {
2980
+ const [status, buckyos2] = await Promise.all([
2981
+ callService(ctx, CONTROL_PANEL$4, "system.status", {}),
2982
+ buckyosInfo(ctx)
2983
+ ]);
2984
+ return { ...expectObject$4(status, "system.status"), buckyos: buckyos2 };
2985
+ }
2986
+ },
2987
+ {
2988
+ verb: "info",
2989
+ summary: "Get the installed BuckyOS version, build version, and release channel",
2990
+ description: "build_version is build<YYMMDD>.<branch>.<commit12>[.dirty]; any authenticated identity may read it.",
2991
+ inputSchema: EMPTY_INPUT$1,
2992
+ outputSchema: BUCKYOS_INFO,
2993
+ resultSchemaVersion: 1,
2994
+ access: { mode: "fixed", level: "read" },
2995
+ asyncMode: "sync",
2996
+ requiresSession: true,
2997
+ examples: ["buckyos system info"],
2998
+ handler: async (ctx) => await buckyosInfo(ctx)
2903
2999
  }
2904
3000
  ]
2905
3001
  };
2906
3002
  }
3003
+ async function buckyosInfo(ctx) {
3004
+ return expectObject$4(
3005
+ await callService(ctx, CONTROL_PANEL$4, "system.buckyos_info.get", {}),
3006
+ "system.buckyos_info.get"
3007
+ );
3008
+ }
2907
3009
  const SERVICE_NAME = "system_config";
2908
- const OBJECT_OUTPUT$6 = { type: "object", additionalProperties: false };
3010
+ const OBJECT_OUTPUT$a = { type: "object", additionalProperties: false };
2909
3011
  const KEY_INPUT = {
2910
3012
  type: "object",
2911
3013
  properties: { key: { type: "string", minLength: 1 } },
@@ -2923,7 +3025,7 @@ function createSystemConfigModule() {
2923
3025
  positionals: [{ name: "key", description: "System-config key" }],
2924
3026
  inputSchema: KEY_INPUT,
2925
3027
  outputSchema: {
2926
- ...OBJECT_OUTPUT$6,
3028
+ ...OBJECT_OUTPUT$a,
2927
3029
  properties: {
2928
3030
  key: { type: "string" },
2929
3031
  value: { type: "string" },
@@ -2950,7 +3052,7 @@ function createSystemConfigModule() {
2950
3052
  );
2951
3053
  }
2952
3054
  if (!isConfigValue(result))
2953
- invalidResponse$2("sys_config_get");
3055
+ invalidResponse$3("sys_config_get");
2954
3056
  return { key, value: result.value, version: result.version, text: result.value };
2955
3057
  }
2956
3058
  },
@@ -2966,7 +3068,7 @@ function createSystemConfigModule() {
2966
3068
  additionalProperties: false
2967
3069
  },
2968
3070
  outputSchema: {
2969
- ...OBJECT_OUTPUT$6,
3071
+ ...OBJECT_OUTPUT$a,
2970
3072
  properties: {
2971
3073
  key: { type: "string" },
2972
3074
  items: { type: "array", items: { type: "string" } }
@@ -2985,7 +3087,7 @@ function createSystemConfigModule() {
2985
3087
  const key = typeof input.key === "string" ? input.key : "";
2986
3088
  const result = await callSystemConfig(ctx, "sys_config_list", { key });
2987
3089
  if (!Array.isArray(result) || !result.every((item) => typeof item === "string")) {
2988
- invalidResponse$2("sys_config_list");
3090
+ invalidResponse$3("sys_config_list");
2989
3091
  }
2990
3092
  return { key, items: result };
2991
3093
  }
@@ -3020,7 +3122,7 @@ function setCommand() {
3020
3122
  additionalProperties: false
3021
3123
  },
3022
3124
  outputSchema: {
3023
- ...OBJECT_OUTPUT$6,
3125
+ ...OBJECT_OUTPUT$a,
3024
3126
  properties: { key: { type: "string" }, updated: { type: "boolean" } },
3025
3127
  required: ["key", "updated"]
3026
3128
  },
@@ -3059,7 +3161,7 @@ function setFileCommand() {
3059
3161
  additionalProperties: false
3060
3162
  },
3061
3163
  outputSchema: {
3062
- ...OBJECT_OUTPUT$6,
3164
+ ...OBJECT_OUTPUT$a,
3063
3165
  properties: { key: { type: "string" }, updated: { type: "boolean" } },
3064
3166
  required: ["key", "updated"]
3065
3167
  },
@@ -3096,7 +3198,7 @@ function mutationCommand(options) {
3096
3198
  additionalProperties: false
3097
3199
  },
3098
3200
  outputSchema: {
3099
- ...OBJECT_OUTPUT$6,
3201
+ ...OBJECT_OUTPUT$a,
3100
3202
  properties: {
3101
3203
  key: { type: "string" },
3102
3204
  [options.resultProperty]: { type: "boolean" }
@@ -3141,7 +3243,7 @@ function isConfigValue(value) {
3141
3243
  const object = value;
3142
3244
  return typeof object.value === "string" && Number.isSafeInteger(object.version) && Number(object.version) >= 0;
3143
3245
  }
3144
- function invalidResponse$2(method) {
3246
+ function invalidResponse$3(method) {
3145
3247
  throw new ToolError(
3146
3248
  "INVALID_SERVICE_RESPONSE",
3147
3249
  `system-config returned an invalid response for ${method}`,
@@ -3228,6 +3330,80 @@ async function createDeterministicTarGz(sourceDir, destination) {
3228
3330
  async function gzipFile(source, destination) {
3229
3331
  await getHost().gzipFile(source, destination);
3230
3332
  }
3333
+ async function readTarGz(bytes, limit) {
3334
+ const tar = await gunzipBytes(bytes, limit);
3335
+ const decoder = new TextDecoder("utf-8", { fatal: true });
3336
+ const text = (offset2, length) => decoder.decode(tar.subarray(offset2, offset2 + length)).replace(/\0.*$/s, "");
3337
+ const files = [];
3338
+ const seen = /* @__PURE__ */ new Set();
3339
+ let offset = 0;
3340
+ while (offset + BLOCK_SIZE <= tar.length && tar.subarray(offset, offset + BLOCK_SIZE).some(Boolean)) {
3341
+ let raw;
3342
+ let size;
3343
+ let mode;
3344
+ try {
3345
+ const prefix = text(offset + 257, 6) === "ustar" ? text(offset + 345, 155) : "";
3346
+ raw = prefix ? `${prefix}/${text(offset, 100)}` : text(offset, 100);
3347
+ size = Number.parseInt(text(offset + 124, 12).trim() || "0", 8);
3348
+ mode = Number.parseInt(text(offset + 100, 8).trim() || "0", 8);
3349
+ } catch {
3350
+ throw invalidZip("payload", "tar header is not valid UTF-8");
3351
+ }
3352
+ const type = String.fromCharCode(tar[offset + 156] || 48);
3353
+ const path = raw.replace(/^(?:\.\/)+/, "").replace(/\/$/, "");
3354
+ const start = offset + BLOCK_SIZE;
3355
+ if (!Number.isSafeInteger(size) || size < 0 || start + size > tar.length) {
3356
+ throw invalidZip("payload", `tar entry is truncated: ${raw}`);
3357
+ }
3358
+ offset = start + Math.ceil(size / BLOCK_SIZE) * BLOCK_SIZE;
3359
+ if (type === "5" && (path === "" || path === "."))
3360
+ continue;
3361
+ if (!path || path.startsWith("/") || /^[A-Za-z]:/.test(path) || path.includes("\\") || path.split("/").some((segment) => !segment || segment === "." || segment === "..")) {
3362
+ throw invalidZip("payload", `unsafe tar entry path: ${JSON.stringify(raw)}`);
3363
+ }
3364
+ if (type === "5")
3365
+ continue;
3366
+ if (type !== "0") {
3367
+ throw invalidZip("payload", `tar entry is not a regular file or directory: ${path}`);
3368
+ }
3369
+ if (seen.has(path))
3370
+ throw invalidZip("payload", `duplicate tar entry: ${path}`);
3371
+ seen.add(path);
3372
+ files.push({ path, executable: (mode & 73) !== 0, bytes: tar.slice(start, start + size) });
3373
+ }
3374
+ return files;
3375
+ }
3376
+ async function gunzipBytes(bytes, limit) {
3377
+ const stream = new ReadableStream({
3378
+ start(controller) {
3379
+ controller.enqueue(bytes);
3380
+ controller.close();
3381
+ }
3382
+ }).pipeThrough(
3383
+ new DecompressionStream("gzip")
3384
+ );
3385
+ const chunks = [];
3386
+ let size = 0;
3387
+ try {
3388
+ for await (const chunk of stream) {
3389
+ size += chunk.length;
3390
+ if (size > limit)
3391
+ throw invalidZip("limits", "payload expands beyond the size limit");
3392
+ chunks.push(chunk);
3393
+ }
3394
+ } catch (error) {
3395
+ if (error instanceof ToolError)
3396
+ throw error;
3397
+ throw invalidZip("compression", "payload is not a valid gzip stream");
3398
+ }
3399
+ const result = new Uint8Array(size);
3400
+ let position = 0;
3401
+ for (const chunk of chunks) {
3402
+ result.set(chunk, position);
3403
+ position += chunk.length;
3404
+ }
3405
+ return result;
3406
+ }
3231
3407
  async function writeStoredZip(destination, sources) {
3232
3408
  if (sources.length > MAX_PIKG_ENTRIES) {
3233
3409
  throw new UsageError("TOO_MANY_ENTRIES", "PIKG contains too many entries");
@@ -4357,6 +4533,8 @@ async function inspectPikg(path) {
4357
4533
  app: {
4358
4534
  did: String(appDoc.did),
4359
4535
  app_id: appIdFromDid(String(appDoc.did)),
4536
+ ...typeof appDoc.name === "string" ? { name: appDoc.name } : {},
4537
+ app_type: String(appDoc.app_type),
4360
4538
  version: String(appDoc.version),
4361
4539
  owner: String(appDoc.owner),
4362
4540
  app_doc_object_id: validated.appDocObjectId
@@ -4617,7 +4795,7 @@ function validateAppDocShape(appDoc) {
4617
4795
  }
4618
4796
  if (appDoc.doc_type !== "app")
4619
4797
  throw invalid("appdoc", "APPDOC.doc_type must be app");
4620
- if (!["service", "dapp", "web", "agent"].includes(String(appDoc.app_type))) {
4798
+ if (!["service", "dapp", "web", "agent", "agent_skills"].includes(String(appDoc.app_type))) {
4621
4799
  throw invalid("appdoc", "APPDOC.app_type is invalid");
4622
4800
  }
4623
4801
  if (appDoc.name !== void 0)
@@ -4669,6 +4847,12 @@ function validateAppDocShape(appDoc) {
4669
4847
  if (Object.keys(pkgList).length === 0) {
4670
4848
  throw invalid("appdoc", "APPDOC.pkg_list must not be empty");
4671
4849
  }
4850
+ if (appDoc.app_type === "agent_skills") {
4851
+ expectNonEmptyString(appDoc.name, "APPDOC.name");
4852
+ if (Object.keys(pkgList).join() !== "agent_skills") {
4853
+ throw invalid("appdoc", "an agent_skills App must contain only the agent_skills sub package");
4854
+ }
4855
+ }
4672
4856
  deriveNamespaceForPackage(appDoc);
4673
4857
  }
4674
4858
  function deriveNamespaceForPackage(appDoc) {
@@ -4922,7 +5106,7 @@ function validateContentHandlers(value, permissions) {
4922
5106
  }
4923
5107
  return value;
4924
5108
  }
4925
- const PACKAGE_VERSION = "0.7.131";
5109
+ const PACKAGE_VERSION = "0.7.133";
4926
5110
  const TOOL_VERSION = PACKAGE_VERSION;
4927
5111
  const SDK_VERSION = PACKAGE_VERSION;
4928
5112
  const PROTOCOL_VERSION = "1";
@@ -4939,7 +5123,13 @@ const VERSION$1 = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
4939
5123
  const SHA256_ID = /^sha256:[0-9a-f]{64}$/;
4940
5124
  const OBJECT_ID = /^(?:appdoc|pkg):[0-9a-f]{64}$/;
4941
5125
  const SAFE_GENERATED_FILE = /^[A-Za-z0-9._-]+$/;
4942
- const OBJECT_OUTPUT$5 = { type: "object", additionalProperties: true };
5126
+ const OBJECT_OUTPUT$9 = { type: "object", additionalProperties: true };
5127
+ const APP_KINDS = ["static-web", "script", "docker", "agent-skills"];
5128
+ const PATH_KINDS = {
5129
+ "static-web": { key: "web", category: "web", selectorType: "static" },
5130
+ script: { key: "script", category: "dapp", selectorType: "single" },
5131
+ "agent-skills": { key: "agent_skills", category: "agent_skills", selectorType: "single" }
5132
+ };
4943
5133
  function packageEnvironmentQualifier(key, selector) {
4944
5134
  const effective = selector ?? derivedSelector(key);
4945
5135
  const os = effective?.os;
@@ -4976,7 +5166,7 @@ function createPikgModule(dependencies = {}) {
4976
5166
  properties: { meta_dir: { type: "string", minLength: 1 } },
4977
5167
  additionalProperties: false
4978
5168
  },
4979
- outputSchema: OBJECT_OUTPUT$5,
5169
+ outputSchema: OBJECT_OUTPUT$9,
4980
5170
  resultSchemaVersion: 1,
4981
5171
  access: { mode: "fixed", level: "read" },
4982
5172
  asyncMode: "sync",
@@ -5000,7 +5190,7 @@ function createPikgModule(dependencies = {}) {
5000
5190
  name: "kind",
5001
5191
  description: "Initial App kind",
5002
5192
  type: "string",
5003
- enum: ["static-web", "script", "docker"]
5193
+ enum: APP_KINDS
5004
5194
  },
5005
5195
  {
5006
5196
  name: "source",
@@ -5016,14 +5206,14 @@ function createPikgModule(dependencies = {}) {
5016
5206
  project_dir: { type: "string", minLength: 1 },
5017
5207
  name: { type: "string", minLength: 1 },
5018
5208
  owner: { type: "string", minLength: 1 },
5019
- kind: { type: "string", enum: ["static-web", "script", "docker"] },
5209
+ kind: { type: "string", enum: APP_KINDS },
5020
5210
  source: { type: "string", minLength: 1 },
5021
5211
  version: { type: "string", minLength: 1 },
5022
5212
  app_did: { type: "string", minLength: 1 }
5023
5213
  },
5024
5214
  additionalProperties: false
5025
5215
  },
5026
- outputSchema: OBJECT_OUTPUT$5,
5216
+ outputSchema: OBJECT_OUTPUT$9,
5027
5217
  resultSchemaVersion: 1,
5028
5218
  access: { mode: "fixed", level: "write" },
5029
5219
  asyncMode: "sync",
@@ -5032,7 +5222,8 @@ function createPikgModule(dependencies = {}) {
5032
5222
  networkAccess: false,
5033
5223
  examples: [
5034
5224
  "buckyos pikg init .",
5035
- "buckyos --non-interactive pikg init . --owner did:bns:root --kind static-web --source ./web/dist"
5225
+ "buckyos --non-interactive pikg init . --owner did:bns:root --kind static-web --source ./web/dist",
5226
+ "buckyos --non-interactive pikg init . --owner did:bns:root --kind agent-skills --source ./skills"
5036
5227
  ],
5037
5228
  handler: async (ctx, input) => await initCommand(ctx, input, docker)
5038
5229
  },
@@ -5047,7 +5238,7 @@ function createPikgModule(dependencies = {}) {
5047
5238
  properties: { meta_dir: { type: "string", minLength: 1 } },
5048
5239
  additionalProperties: false
5049
5240
  },
5050
- outputSchema: OBJECT_OUTPUT$5,
5241
+ outputSchema: OBJECT_OUTPUT$9,
5051
5242
  resultSchemaVersion: 1,
5052
5243
  access: { mode: "fixed", level: "write" },
5053
5244
  asyncMode: "sync",
@@ -5068,7 +5259,7 @@ function createPikgModule(dependencies = {}) {
5068
5259
  properties: { dist_dir: { type: "string", minLength: 1 } },
5069
5260
  additionalProperties: false
5070
5261
  },
5071
- outputSchema: OBJECT_OUTPUT$5,
5262
+ outputSchema: OBJECT_OUTPUT$9,
5072
5263
  resultSchemaVersion: 1,
5073
5264
  access: { mode: "fixed", level: "write" },
5074
5265
  asyncMode: "sync",
@@ -5088,7 +5279,7 @@ function createPikgModule(dependencies = {}) {
5088
5279
  required: ["pikg_path"],
5089
5280
  additionalProperties: false
5090
5281
  },
5091
- outputSchema: OBJECT_OUTPUT$5,
5282
+ outputSchema: OBJECT_OUTPUT$9,
5092
5283
  resultSchemaVersion: 1,
5093
5284
  access: { mode: "fixed", level: "read" },
5094
5285
  asyncMode: "sync",
@@ -5109,7 +5300,7 @@ function createPikgModule(dependencies = {}) {
5109
5300
  properties: { meta_dir: { type: "string", minLength: 1 } },
5110
5301
  additionalProperties: false
5111
5302
  },
5112
- outputSchema: OBJECT_OUTPUT$5,
5303
+ outputSchema: OBJECT_OUTPUT$9,
5113
5304
  resultSchemaVersion: 1,
5114
5305
  access: { mode: "fixed", level: "destructive" },
5115
5306
  asyncMode: "sync",
@@ -5234,11 +5425,11 @@ async function initCommand(ctx, input, docker) {
5234
5425
  kind = await requiredPrompt(
5235
5426
  ctx,
5236
5427
  canPrompt,
5237
- "App kind (static-web/script/docker): ",
5428
+ `App kind (${APP_KINDS.join("/")}): `,
5238
5429
  "kind"
5239
5430
  );
5240
5431
  }
5241
- if (!["static-web", "script", "docker"].includes(kind)) {
5432
+ if (!APP_KINDS.includes(kind)) {
5242
5433
  throw new UsageError("INVALID_APP_KIND", `invalid App kind: ${kind}`);
5243
5434
  }
5244
5435
  let source = optionalInputString(input, "source");
@@ -5264,7 +5455,7 @@ async function initCommand(ctx, input, docker) {
5264
5455
  sourceValue = { type: "docker-image", image: source };
5265
5456
  sourceSummary2 = { type: "docker-image", image: image.canonicalName, image_id: image.id };
5266
5457
  } else {
5267
- subpackageKey = kind === "static-web" ? "web" : "script";
5458
+ subpackageKey = PATH_KINDS[kind].key;
5268
5459
  const absoluteSource = resolve$1(projectDir, source);
5269
5460
  const persistedSource = isAbsolute$1(source) ? resolve$1(source) : toPortablePath(relative(join(projectDir, "dapp_meta"), absoluteSource));
5270
5461
  sourceValue = { type: "path", path: persistedSource };
@@ -5287,9 +5478,9 @@ async function initCommand(ctx, input, docker) {
5287
5478
  owner,
5288
5479
  author: owner,
5289
5480
  show_name: name,
5290
- categories: [kind === "static-web" ? "web" : "dapp"],
5481
+ categories: [PATH_KINDS[kind]?.category ?? "dapp"],
5291
5482
  permissions: [],
5292
- selector_type: kind === "static-web" ? "static" : "single",
5483
+ selector_type: PATH_KINDS[kind]?.selectorType ?? "single",
5293
5484
  service_config_tips: {}
5294
5485
  };
5295
5486
  const pikgMeta = {
@@ -6298,11 +6489,11 @@ async function observeTask(ctx, taskId) {
6298
6489
  TASK_MANAGER_SERVICE,
6299
6490
  "get_task",
6300
6491
  { task_id: taskId },
6301
- rpcOptions$2(ctx)
6492
+ rpcOptions$1(ctx)
6302
6493
  );
6303
6494
  const envelope = expectObject$2(response, "TaskManager get_task response");
6304
6495
  const task = expectObject$2(envelope.task ?? envelope, "TaskManager task");
6305
- const phase = expectString$2(task.phase, "task.phase");
6496
+ const phase = expectString$1(task.phase, "task.phase");
6306
6497
  const outcome = optionalString$2(task.outcome);
6307
6498
  const taskError = isObject$1(task.error) ? task.error : void 0;
6308
6499
  return {
@@ -6320,7 +6511,7 @@ async function observeTask(ctx, taskId) {
6320
6511
  data: task
6321
6512
  };
6322
6513
  }
6323
- function rpcOptions$2(ctx) {
6514
+ function rpcOptions$1(ctx) {
6324
6515
  return {
6325
6516
  traceId: ctx.traceId,
6326
6517
  timeoutMs: Math.max(1, (ctx.deadline ?? Date.now()) - Date.now()),
@@ -6335,7 +6526,7 @@ function normalizeTaskErrorCode(code, outcome) {
6335
6526
  function optionalString$2(value) {
6336
6527
  return typeof value === "string" ? value : void 0;
6337
6528
  }
6338
- function expectString$2(value, label) {
6529
+ function expectString$1(value, label) {
6339
6530
  if (typeof value !== "string" || !value) {
6340
6531
  throw new ToolError("INVALID_SERVICE_RESPONSE", `${label} must be a string`, 9);
6341
6532
  }
@@ -6372,7 +6563,7 @@ const CONTROL_PANEL_SERVICE = "control-panel";
6372
6563
  const PLAN_SCHEMA_VERSION = 4;
6373
6564
  const STAGING_RELEASE_TIMEOUT_MS = 5e3;
6374
6565
  const ZIP_LOCAL_MAGIC = [80, 75, 3, 4];
6375
- const OBJECT_OUTPUT$4 = { type: "object", additionalProperties: true };
6566
+ const OBJECT_OUTPUT$8 = { type: "object", additionalProperties: true };
6376
6567
  const INSTALL_POLICIES = [
6377
6568
  "strict-public",
6378
6569
  "normal",
@@ -6383,8 +6574,8 @@ const INSTALL_POLICIES = [
6383
6574
  function createAppModule(dependencies = {}) {
6384
6575
  const commands = [
6385
6576
  fetchCommand(dependencies),
6386
- listCommand$1(),
6387
- getCommand$1(),
6577
+ listCommand$2(),
6578
+ getCommand$2(),
6388
6579
  installCommand(dependencies),
6389
6580
  upgradeCommand(dependencies),
6390
6581
  uninstallCommand(dependencies),
@@ -6392,7 +6583,8 @@ function createAppModule(dependencies = {}) {
6392
6583
  lifecycleCommand("start", "Start an installed App"),
6393
6584
  lifecycleCommand("stop", "Stop an installed App"),
6394
6585
  restartCommand(),
6395
- statusCommand$1()
6586
+ statusCommand$1(),
6587
+ publishCommand()
6396
6588
  ];
6397
6589
  return {
6398
6590
  name: "app",
@@ -6422,14 +6614,14 @@ function cancelCommand$1() {
6422
6614
  required: ["task_id"],
6423
6615
  additionalProperties: false
6424
6616
  },
6425
- outputSchema: OBJECT_OUTPUT$4,
6617
+ outputSchema: OBJECT_OUTPUT$8,
6426
6618
  resultSchemaVersion: 1,
6427
6619
  access: { mode: "fixed", level: "write" },
6428
6620
  asyncMode: "sync",
6429
6621
  requiresSession: true,
6430
6622
  examples: ["buckyos app cancel t-0123456789abcdef0123456789abcdef --force"],
6431
6623
  handler: async (ctx, input) => await callControl(ctx, "apps.install.cancel", {
6432
- task_id: expectString$1(input, "task_id"),
6624
+ task_id: expectString(input, "task_id"),
6433
6625
  force: input.force === true
6434
6626
  })
6435
6627
  };
@@ -6457,7 +6649,7 @@ function fetchCommand(dependencies) {
6457
6649
  target: { type: "object", additionalProperties: true },
6458
6650
  install_params: { type: "object", additionalProperties: true }
6459
6651
  }),
6460
- outputSchema: OBJECT_OUTPUT$4,
6652
+ outputSchema: OBJECT_OUTPUT$8,
6461
6653
  resultSchemaVersion: 1,
6462
6654
  access: { mode: "fixed", level: "read" },
6463
6655
  asyncMode: "sync",
@@ -6469,12 +6661,12 @@ function fetchCommand(dependencies) {
6469
6661
  handler: async (ctx, input) => await fetchApp(ctx, input, dependencies)
6470
6662
  };
6471
6663
  }
6472
- function listCommand$1() {
6664
+ function listCommand$2() {
6473
6665
  return {
6474
6666
  verb: "list",
6475
6667
  summary: "List visible installed Apps",
6476
6668
  inputSchema: emptyInputSchema(),
6477
- outputSchema: OBJECT_OUTPUT$4,
6669
+ outputSchema: OBJECT_OUTPUT$8,
6478
6670
  resultSchemaVersion: 1,
6479
6671
  access: { mode: "fixed", level: "read" },
6480
6672
  asyncMode: "sync",
@@ -6483,14 +6675,14 @@ function listCommand$1() {
6483
6675
  handler: async (ctx) => await callControl(ctx, "apps.list", {})
6484
6676
  };
6485
6677
  }
6486
- function getCommand$1() {
6678
+ function getCommand$2() {
6487
6679
  return selectorCommand({
6488
6680
  verb: "get",
6489
6681
  summary: "Get installation and runtime details for one App",
6490
6682
  access: "read",
6491
6683
  asyncMode: "sync",
6492
6684
  handler: async (ctx, input) => {
6493
- const selector = normalizeAppSelector(expectString$1(input, "app_name"));
6685
+ const selector = normalizeAppSelector(expectString(input, "app_name"));
6494
6686
  const [details, status] = await Promise.all([
6495
6687
  callControl(ctx, "apps.details", { selector }),
6496
6688
  callControl(ctx, "apps.status", { selector })
@@ -6532,7 +6724,7 @@ function installCommand(dependencies) {
6532
6724
  no_wait: { type: "boolean" },
6533
6725
  policy: { type: "string", enum: [...INSTALL_POLICIES] }
6534
6726
  }),
6535
- outputSchema: OBJECT_OUTPUT$4,
6727
+ outputSchema: OBJECT_OUTPUT$8,
6536
6728
  resultSchemaVersion: 1,
6537
6729
  access: { mode: "fixed", level: "write" },
6538
6730
  asyncMode: "either",
@@ -6576,7 +6768,7 @@ function upgradeCommand(dependencies) {
6576
6768
  },
6577
6769
  additionalProperties: false
6578
6770
  },
6579
- outputSchema: OBJECT_OUTPUT$4,
6771
+ outputSchema: OBJECT_OUTPUT$8,
6580
6772
  resultSchemaVersion: 1,
6581
6773
  access: { mode: "fixed", level: "write" },
6582
6774
  asyncMode: "either",
@@ -6629,11 +6821,11 @@ function uninstallCommand(dependencies) {
6629
6821
  examples: ["buckyos app uninstall app1 --data retain"]
6630
6822
  };
6631
6823
  }
6632
- function lifecycleCommand(verb, summary) {
6824
+ function lifecycleCommand(verb, summary2) {
6633
6825
  return {
6634
6826
  ...selectorCommand({
6635
6827
  verb,
6636
- summary,
6828
+ summary: summary2,
6637
6829
  access: "write",
6638
6830
  asyncMode: verb === "start" ? "task" : "either",
6639
6831
  handler: async (ctx, input) => await mutateLifecycle(ctx, input, verb)
@@ -6705,7 +6897,7 @@ function statusCommand$1() {
6705
6897
  properties: { app_name: { type: "string", minLength: 1 } },
6706
6898
  additionalProperties: false
6707
6899
  },
6708
- outputSchema: OBJECT_OUTPUT$4,
6900
+ outputSchema: OBJECT_OUTPUT$8,
6709
6901
  resultSchemaVersion: 1,
6710
6902
  access: { mode: "fixed", level: "read" },
6711
6903
  asyncMode: "sync",
@@ -6719,17 +6911,17 @@ function statusCommand$1() {
6719
6911
  callControl(ctx, "apps.details", { selector })
6720
6912
  ]);
6721
6913
  const detailObject = expectObject$1(details, "apps.details response");
6722
- const summary = expectObject$1(detailObject.summary, "apps.details summary");
6914
+ const summary2 = expectObject$1(detailObject.summary, "apps.details summary");
6723
6915
  return {
6724
6916
  ...expectObject$1(status, "apps.status response"),
6725
- web_hosts: Array.isArray(summary.web_hosts) ? summary.web_hosts : []
6917
+ web_hosts: Array.isArray(summary2.web_hosts) ? summary2.web_hosts : []
6726
6918
  };
6727
6919
  }
6728
6920
  const listed = expectObject$1(await callControl(ctx, "apps.list", {}), "apps.list response");
6729
6921
  const apps = Array.isArray(listed.apps) ? listed.apps : [];
6730
6922
  const items = await Promise.all(apps.map(async (item) => {
6731
6923
  const app = expectObject$1(item, "apps.list item");
6732
- const selector = expectString$1(app, "app_instance_id");
6924
+ const selector = expectString(app, "app_instance_id");
6733
6925
  return {
6734
6926
  ...expectObject$1(
6735
6927
  await callControl(ctx, "apps.status", { selector }),
@@ -6742,6 +6934,89 @@ function statusCommand$1() {
6742
6934
  }
6743
6935
  };
6744
6936
  }
6937
+ function publishCommand() {
6938
+ return {
6939
+ verb: "publish",
6940
+ summary: "Package a directory on the control-panel node into the Zone Repo as an App candidate",
6941
+ description: "Calls control-panel app.publish: packages <local_dir> (a path on the control-panel node; nothing is uploaded) with the AppDoc template, stores PackageMeta and the AppDoc in the Zone Repo/NamedStore, and stages a self-checked PIKG there. The AppDoc is not Owner-signed and no BNS/App DID record is updated, so this is not an authoritative App release.",
6942
+ positionals: [
6943
+ { name: "local_dir", description: "Absolute source directory on the control-panel node" }
6944
+ ],
6945
+ options: [
6946
+ {
6947
+ name: "app-doc",
6948
+ property: "app_doc",
6949
+ description: "AppDoc template JSON file (pkg_list entries without pkg_objid)",
6950
+ type: "string",
6951
+ required: true
6952
+ },
6953
+ {
6954
+ name: "app-type",
6955
+ property: "app_type",
6956
+ description: "App type; defaults to the template app_type",
6957
+ type: "string",
6958
+ enum: ["dapp", "web", "agent"]
6959
+ }
6960
+ ],
6961
+ inputSchema: {
6962
+ type: "object",
6963
+ properties: {
6964
+ local_dir: { type: "string", minLength: 1 },
6965
+ app_doc: { type: "string", minLength: 1 },
6966
+ app_type: { type: "string", enum: ["dapp", "web", "agent"] }
6967
+ },
6968
+ required: ["local_dir", "app_doc"],
6969
+ additionalProperties: false
6970
+ },
6971
+ outputSchema: OBJECT_OUTPUT$8,
6972
+ resultSchemaVersion: 1,
6973
+ access: { mode: "fixed", level: "write" },
6974
+ asyncMode: "sync",
6975
+ requiresSession: true,
6976
+ examples: [
6977
+ "buckyos app publish /srv/build/demo-web --app-doc ./demo-web.appdoc.json",
6978
+ "buckyos app publish /srv/build/demo-agent --app-doc ./demo-agent.appdoc.json --app-type agent"
6979
+ ],
6980
+ handler: async (ctx, input) => {
6981
+ const localDir = expectString(input, "local_dir");
6982
+ if (!isAbsolute(localDir)) {
6983
+ throw new UsageError(
6984
+ "INVALID_ARGUMENT",
6985
+ "local_dir must be an absolute path on the control-panel node"
6986
+ );
6987
+ }
6988
+ let appDoc;
6989
+ try {
6990
+ appDoc = JSON.parse(
6991
+ await getHost().readTextFile(resolveFromCwd(ctx, expectString(input, "app_doc")))
6992
+ );
6993
+ } catch (error) {
6994
+ throw new UsageError(
6995
+ "INVALID_APP_DOC",
6996
+ `failed to read AppDoc template: ${errorMessage(error)}`
6997
+ );
6998
+ }
6999
+ if (!isObject(appDoc)) {
7000
+ throw new UsageError("INVALID_APP_DOC", "AppDoc template must be a JSON object");
7001
+ }
7002
+ const result = expectObject$1(
7003
+ await callControl(ctx, "app.publish", {
7004
+ local_dir: localDir,
7005
+ app_doc: appDoc,
7006
+ ...typeof input.app_type === "string" ? { app_type: input.app_type } : {}
7007
+ }),
7008
+ "app.publish response"
7009
+ );
7010
+ const { ok: _ok, ...published } = result;
7011
+ return {
7012
+ ...published,
7013
+ publish_status: expectString(result, "publish_status"),
7014
+ app_doc_signature: "not-signed",
7015
+ app_did_publication: "not-published"
7016
+ };
7017
+ }
7018
+ };
7019
+ }
6745
7020
  async function fetchApp(ctx, input, dependencies) {
6746
7021
  const source = await prepareSource(ctx, input, "inspect", dependencies);
6747
7022
  try {
@@ -6777,8 +7052,8 @@ async function installApp(ctx, input, dependencies) {
6777
7052
  let inspection = submittedPlan ? await recomputePlan(ctx, source, input, submittedPlan) : await inspectSource(ctx, source, input);
6778
7053
  verifyPikgBinding(source, submittedPlan ?? inspection.plan);
6779
7054
  const app = expectObject$1(inspection.plan.app, "inspection.plan.app");
6780
- const appDid = expectString$1(app, "did");
6781
- const plannedOwner = submittedPlan ? expectString$1(submittedPlan, "owner_user_id") : void 0;
7055
+ const appDid = expectString(app, "did");
7056
+ const plannedOwner = submittedPlan ? expectString(submittedPlan, "owner_user_id") : void 0;
6782
7057
  const installed = await findInstalled(ctx, appDid, plannedOwner);
6783
7058
  if (submittedPlan && installed) {
6784
7059
  throw new ToolError(
@@ -6816,7 +7091,7 @@ async function installApp(ctx, input, dependencies) {
6816
7091
  ...planScopeAndOptions(inspection.plan),
6817
7092
  options: installOptions(input),
6818
7093
  plan: submittedPlan ?? inspection.plan,
6819
- approved_plan_fingerprint: expectString$1(inspection.plan, "plan_fingerprint"),
7094
+ approved_plan_fingerprint: expectString(inspection.plan, "plan_fingerprint"),
6820
7095
  idempotency_key: idempotencyKey(ctx)
6821
7096
  };
6822
7097
  const submitted = expectObject$1(
@@ -6826,7 +7101,7 @@ async function installApp(ctx, input, dependencies) {
6826
7101
  if (submitted.action === "satisfied" || submitted.task_id === null) {
6827
7102
  return submitted;
6828
7103
  }
6829
- const taskId = expectString$1(submitted, "task_id");
7104
+ const taskId = expectString(submitted, "task_id");
6830
7105
  keepStaging = true;
6831
7106
  if (input.no_wait === true)
6832
7107
  return submitted;
@@ -6869,7 +7144,7 @@ async function upgradeApps(ctx, input, dependencies) {
6869
7144
  let installTask = false;
6870
7145
  if (selector) {
6871
7146
  const item = expectObject$1(actionable[0], "upgrade item");
6872
- const appDid = expectString$1(item, "app_did");
7147
+ const appDid = expectString(item, "app_did");
6873
7148
  const details = await findInstalled(ctx, appDid);
6874
7149
  if (!details)
6875
7150
  throw new ToolError("RESOURCE_NOT_FOUND", `App is not installed: ${appDid}`);
@@ -6888,7 +7163,7 @@ async function upgradeApps(ctx, input, dependencies) {
6888
7163
  ...planScopeAndOptions(inspection.plan),
6889
7164
  options: installOptions(input),
6890
7165
  plan: inspection.plan,
6891
- approved_plan_fingerprint: expectString$1(inspection.plan, "plan_fingerprint"),
7166
+ approved_plan_fingerprint: expectString(inspection.plan, "plan_fingerprint"),
6892
7167
  idempotency_key: idempotencyKey(ctx)
6893
7168
  }),
6894
7169
  "apps.submit response"
@@ -6902,7 +7177,7 @@ async function upgradeApps(ctx, input, dependencies) {
6902
7177
  }
6903
7178
  if (submitted.task_id === null || submitted.action === "satisfied")
6904
7179
  return submitted;
6905
- const taskId = expectString$1(submitted, "task_id");
7180
+ const taskId = expectString(submitted, "task_id");
6906
7181
  if (input.no_wait === true)
6907
7182
  return submitted;
6908
7183
  const status = await waitForTask(ctx, taskId, {
@@ -6913,7 +7188,7 @@ async function upgradeApps(ctx, input, dependencies) {
6913
7188
  }
6914
7189
  async function uninstallApp(ctx, input, dependencies) {
6915
7190
  rejectDryRunNoWait(input);
6916
- const selector = normalizeAppSelector(expectString$1(input, "app_name"));
7191
+ const selector = normalizeAppSelector(expectString(input, "app_name"));
6917
7192
  const status = await callControl(ctx, "apps.status", { selector });
6918
7193
  const preflight = { action: "uninstall", data_disposition: input.data, status };
6919
7194
  if (input.dry_run === true)
@@ -6927,7 +7202,7 @@ async function uninstallApp(ctx, input, dependencies) {
6927
7202
  }),
6928
7203
  "apps.uninstall response"
6929
7204
  );
6930
- const taskId = expectString$1(submitted, "task_id");
7205
+ const taskId = expectString(submitted, "task_id");
6931
7206
  if (input.no_wait === true)
6932
7207
  return submitted;
6933
7208
  const task = await waitForTask(ctx, taskId, { sleep: dependencies.sleep });
@@ -6940,7 +7215,7 @@ async function mutateLifecycle(ctx, input, verb) {
6940
7215
  "rolling restart is not supported by the current deployment strategy"
6941
7216
  );
6942
7217
  }
6943
- const selector = normalizeAppSelector(expectString$1(input, "app_name"));
7218
+ const selector = normalizeAppSelector(expectString(input, "app_name"));
6944
7219
  const submitted = expectObject$1(
6945
7220
  await callControl(ctx, `apps.${verb}`, {
6946
7221
  selector,
@@ -6949,7 +7224,7 @@ async function mutateLifecycle(ctx, input, verb) {
6949
7224
  }),
6950
7225
  `apps.${verb} response`
6951
7226
  );
6952
- const taskId = expectString$1(submitted, "task_id");
7227
+ const taskId = expectString(submitted, "task_id");
6953
7228
  if (input.no_wait === true)
6954
7229
  return submitted;
6955
7230
  const task = await waitForTask(ctx, taskId);
@@ -7210,7 +7485,7 @@ async function stagePikg(ctx, snapshot, purpose) {
7210
7485
  throw new ToolError("AUTH_REQUIRED", "authenticated session is required", 3);
7211
7486
  const token = (await session.ensureValid()).token;
7212
7487
  const proxy = ndm_proxy.createNdmProxyClient({
7213
- endpoint: gatewayOrigin(ctx.connection.endpoint),
7488
+ endpoint: gatewayOrigin$1(ctx.connection.endpoint),
7214
7489
  sessionToken: token,
7215
7490
  fetcher: (request, init) => fetch(normalizeNdmRequestUrl(request), { ...init, signal: ctx.signal })
7216
7491
  });
@@ -7266,10 +7541,10 @@ async function stagePikg(ctx, snapshot, purpose) {
7266
7541
  function parseStagingMetadata(value) {
7267
7542
  return {
7268
7543
  schema_version: expectNumber(value, "schema_version"),
7269
- handle: expectString$1(value, "handle"),
7270
- pikg_digest: expectString$1(value, "pikg_digest"),
7544
+ handle: expectString(value, "handle"),
7545
+ pikg_digest: expectString(value, "pikg_digest"),
7271
7546
  size: expectNumber(value, "size"),
7272
- purpose: expectString$1(value, "purpose"),
7547
+ purpose: expectString(value, "purpose"),
7273
7548
  expires_at: optionalNumber(value.expires_at)
7274
7549
  };
7275
7550
  }
@@ -7362,7 +7637,7 @@ async function observeInstallTask(ctx, taskId) {
7362
7637
  const error = isObject(status.error) ? status.error : void 0;
7363
7638
  const sanitizedDetails = error && isObject(error.details) ? sanitizeAppOutput(error.details) : void 0;
7364
7639
  return {
7365
- phase: expectString$1(status, "task_phase"),
7640
+ phase: expectString(status, "task_phase"),
7366
7641
  outcome: optionalString$1(status.task_outcome),
7367
7642
  message: installProgressMessage(status),
7368
7643
  error: error ? {
@@ -7374,8 +7649,8 @@ async function observeInstallTask(ctx, taskId) {
7374
7649
  data: status
7375
7650
  };
7376
7651
  }
7377
- async function confirmChange(ctx, action, summary) {
7378
- await ctx.io.stderr(`${JSON.stringify({ action, preflight: summary }, null, 2)}
7652
+ async function confirmChange(ctx, action, summary2) {
7653
+ await ctx.io.stderr(`${JSON.stringify({ action, preflight: summary2 }, null, 2)}
7379
7654
  `);
7380
7655
  if (ctx.confirmed)
7381
7656
  return;
@@ -7393,7 +7668,7 @@ async function confirmChange(ctx, action, summary) {
7393
7668
  }
7394
7669
  async function callControl(ctx, method, params) {
7395
7670
  try {
7396
- return await ctx.clients.call(CONTROL_PANEL_SERVICE, method, params, rpcOptions$1(ctx));
7671
+ return await ctx.clients.call(CONTROL_PANEL_SERVICE, method, params, rpcOptions(ctx));
7397
7672
  } catch (error) {
7398
7673
  throw normalizeAppServiceError(error);
7399
7674
  }
@@ -7454,14 +7729,14 @@ function scopeAndChoiceParams(input) {
7454
7729
  }
7455
7730
  function planScopeAndOptions(plan) {
7456
7731
  return {
7457
- owner_user_id: expectString$1(plan, "owner_user_id"),
7732
+ owner_user_id: expectString(plan, "owner_user_id"),
7458
7733
  target: expectObject$1(plan.target, "plan.target"),
7459
7734
  install_params: expectObject$1(plan.install_params, "plan.install_params")
7460
7735
  };
7461
7736
  }
7462
7737
  function installedScope(details) {
7463
7738
  return {
7464
- owner_user_id: expectString$1(details, "owner_user_id")
7739
+ owner_user_id: expectString(details, "owner_user_id")
7465
7740
  };
7466
7741
  }
7467
7742
  function installOptions(input) {
@@ -7502,7 +7777,7 @@ function satisfiedResult(inspection) {
7502
7777
  };
7503
7778
  }
7504
7779
  function assertPlanMatchesInspection(plan, inspection) {
7505
- const fingerprint = expectString$1(plan, "plan_fingerprint");
7780
+ const fingerprint = expectString(plan, "plan_fingerprint");
7506
7781
  if (fingerprint !== inspection.plan.plan_fingerprint) {
7507
7782
  throw new ToolError(
7508
7783
  "PLAN_STALE",
@@ -7520,7 +7795,7 @@ function verifyPikgBinding(source, plan) {
7520
7795
  if (source.kind === "catalog")
7521
7796
  return;
7522
7797
  const identity = expectObject$1(plan.source_identity, "plan.source_identity");
7523
- const digest = expectString$1(identity, "pikg_digest");
7798
+ const digest = expectString(identity, "pikg_digest");
7524
7799
  if (digest !== source.snapshot.digest) {
7525
7800
  throw new ToolError(
7526
7801
  "PLAN_STALE",
@@ -7538,8 +7813,8 @@ function assertPortablePlan(plan) {
7538
7813
  `InstallPlan schema must be v${PLAN_SCHEMA_VERSION}`
7539
7814
  );
7540
7815
  }
7541
- expectString$1(plan, "plan_fingerprint");
7542
- expectString$1(plan, "task_id");
7816
+ expectString(plan, "plan_fingerprint");
7817
+ expectString(plan, "task_id");
7543
7818
  const allowed = /* @__PURE__ */ new Set([
7544
7819
  "schema_version",
7545
7820
  "plan_use",
@@ -7747,7 +8022,7 @@ function validatePikgSnapshot(bytes) {
7747
8022
  throw new UsageError("INVALID_PIKG", "PIKG magic mismatch: expected a ZIP container");
7748
8023
  }
7749
8024
  }
7750
- function gatewayOrigin(endpoint) {
8025
+ function gatewayOrigin$1(endpoint) {
7751
8026
  const url = new URL(endpoint);
7752
8027
  const marker = url.pathname.indexOf("/kapi");
7753
8028
  url.pathname = marker >= 0 ? url.pathname.slice(0, marker) || "/" : "/";
@@ -7819,7 +8094,7 @@ function selectorCommand(options) {
7819
8094
  required: ["app_name"],
7820
8095
  additionalProperties: false
7821
8096
  },
7822
- outputSchema: OBJECT_OUTPUT$4,
8097
+ outputSchema: OBJECT_OUTPUT$8,
7823
8098
  resultSchemaVersion: 1,
7824
8099
  access: { mode: "fixed", level: options.access },
7825
8100
  asyncMode: options.asyncMode,
@@ -7871,7 +8146,7 @@ function policyOption() {
7871
8146
  enum: [...INSTALL_POLICIES]
7872
8147
  };
7873
8148
  }
7874
- function rpcOptions$1(ctx) {
8149
+ function rpcOptions(ctx) {
7875
8150
  return {
7876
8151
  traceId: ctx.traceId,
7877
8152
  timeoutMs: Math.max(1, (ctx.deadline ?? Date.now()) - Date.now()),
@@ -7887,7 +8162,7 @@ function expectObject$1(value, label) {
7887
8162
  function isObject(value) {
7888
8163
  return !!value && typeof value === "object" && !Array.isArray(value);
7889
8164
  }
7890
- function expectString$1(value, property) {
8165
+ function expectString(value, property) {
7891
8166
  const candidate = isObject(value) ? value[property] : value;
7892
8167
  if (typeof candidate !== "string" || !candidate.trim()) {
7893
8168
  throw new ToolError("INVALID_SERVICE_RESPONSE", `${property} must be a non-empty string`, 9);
@@ -7982,71 +8257,8 @@ async function defaultArtifactFetcher(url, ctx) {
7982
8257
  function toHex(bytes) {
7983
8258
  return [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
7984
8259
  }
7985
- function rpcOptions(ctx) {
7986
- return {
7987
- traceId: ctx.traceId,
7988
- timeoutMs: Math.max(1, (ctx.deadline ?? Date.now()) - Date.now()),
7989
- signal: ctx.signal
7990
- };
7991
- }
7992
- async function callService(ctx, service, method, params) {
7993
- try {
7994
- return await ctx.clients.call(service, method, params, rpcOptions(ctx));
7995
- } catch (error) {
7996
- const message = error instanceof Error ? error.message : String(error);
7997
- const stable = message.match(/\b((?:TASK|AUDIT|DIAGNOSTIC|LOG)_[A-Z0-9_]+):/);
7998
- if (stable)
7999
- throw new ToolError(stable[1], message);
8000
- throw error;
8001
- }
8002
- }
8003
- function expectObject(value, label) {
8004
- if (!value || typeof value !== "object" || Array.isArray(value)) {
8005
- throw new ToolError("INVALID_SERVICE_RESPONSE", `${label} must be an object`, EXIT_INTERNAL);
8006
- }
8007
- return value;
8008
- }
8009
- function expectString(value, label) {
8010
- if (typeof value !== "string" || !value.trim()) {
8011
- throw new ToolError("INVALID_SERVICE_RESPONSE", `${label} must be a string`, EXIT_INTERNAL);
8012
- }
8013
- return value;
8014
- }
8015
- function inputString(input, key) {
8016
- const value = input[key];
8017
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
8018
- }
8019
- function requiredInputString(input, key) {
8020
- const value = inputString(input, key);
8021
- if (!value)
8022
- throw new UsageError("INVALID_ARGUMENT", `${key} is required`);
8023
- return value;
8024
- }
8025
- function parseTimestamp(value, key) {
8026
- if (value === void 0)
8027
- return void 0;
8028
- if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0)
8029
- return value;
8030
- if (typeof value !== "string" || !value.trim()) {
8031
- throw new UsageError("INVALID_ARGUMENT", `${key} must be RFC 3339 or Unix milliseconds`);
8032
- }
8033
- if (/^\d+$/.test(value)) {
8034
- const milliseconds2 = Number(value);
8035
- if (Number.isSafeInteger(milliseconds2))
8036
- return milliseconds2;
8037
- }
8038
- const milliseconds = Date.parse(value);
8039
- if (!Number.isFinite(milliseconds)) {
8040
- throw new UsageError("INVALID_ARGUMENT", `${key} must be RFC 3339 or Unix milliseconds`);
8041
- }
8042
- return milliseconds;
8043
- }
8044
- function splitServices(value) {
8045
- const items = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
8046
- return [...new Set(items.map((item) => String(item).trim()).filter(Boolean))];
8047
- }
8048
- const CONTROL_PANEL$2 = "control-panel";
8049
- const OBJECT_OUTPUT$3 = { type: "object", additionalProperties: true };
8260
+ const CONTROL_PANEL$3 = "control-panel";
8261
+ const OBJECT_OUTPUT$7 = { type: "object", additionalProperties: true };
8050
8262
  function createDiagnosticModule(dependencies = {}) {
8051
8263
  return {
8052
8264
  name: "diagnostic",
@@ -8085,7 +8297,7 @@ function collectCommand() {
8085
8297
  required: ["services"],
8086
8298
  additionalProperties: false
8087
8299
  },
8088
- outputSchema: OBJECT_OUTPUT$3,
8300
+ outputSchema: OBJECT_OUTPUT$7,
8089
8301
  resultSchemaVersion: 1,
8090
8302
  access: { mode: "fixed", level: "privileged" },
8091
8303
  asyncMode: "task",
@@ -8098,10 +8310,10 @@ function collectCommand() {
8098
8310
  if (services.length === 0) {
8099
8311
  throw new UsageError("INVALID_ARGUMENT", "at least one diagnostic service is required");
8100
8312
  }
8101
- const response = expectObject(
8313
+ const response = expectObject$4(
8102
8314
  await callService(
8103
8315
  ctx,
8104
- CONTROL_PANEL$2,
8316
+ CONTROL_PANEL$3,
8105
8317
  "diagnostic.collect",
8106
8318
  compact$2({
8107
8319
  services,
@@ -8112,7 +8324,7 @@ function collectCommand() {
8112
8324
  ),
8113
8325
  "Control Panel diagnostic.collect response"
8114
8326
  );
8115
- const taskId = expectString(response.task_id, "diagnostic.collect.task_id");
8327
+ const taskId = expectString$2(response.task_id, "diagnostic.collect.task_id");
8116
8328
  if (input.no_wait === true)
8117
8329
  return { task_id: taskId };
8118
8330
  return await waitForTask(ctx, taskId);
@@ -8139,7 +8351,7 @@ function exportCommand$1(dependencies) {
8139
8351
  required: ["bundle_id", "path"],
8140
8352
  additionalProperties: false
8141
8353
  },
8142
- outputSchema: OBJECT_OUTPUT$3,
8354
+ outputSchema: OBJECT_OUTPUT$7,
8143
8355
  resultSchemaVersion: 1,
8144
8356
  access: { mode: "fixed", level: "privileged" },
8145
8357
  asyncMode: "sync",
@@ -8149,16 +8361,16 @@ function exportCommand$1(dependencies) {
8149
8361
  };
8150
8362
  }
8151
8363
  async function exportDiagnostic(ctx, input, dependencies) {
8152
- const response = expectObject(
8153
- await callService(ctx, CONTROL_PANEL$2, "diagnostic.export", {
8364
+ const response = expectObject$4(
8365
+ await callService(ctx, CONTROL_PANEL$3, "diagnostic.export", {
8154
8366
  bundle_id: requiredInputString(input, "bundle_id")
8155
8367
  }),
8156
8368
  "Control Panel diagnostic.export response"
8157
8369
  );
8158
8370
  const downloaded = await downloadArtifact(
8159
8371
  ctx,
8160
- CONTROL_PANEL$2,
8161
- expectString(response.url, "diagnostic.export.url"),
8372
+ CONTROL_PANEL$3,
8373
+ expectString$2(response.url, "diagnostic.export.url"),
8162
8374
  requiredInputString(input, "path"),
8163
8375
  dependencies.download
8164
8376
  );
@@ -8180,25 +8392,58 @@ async function exportDiagnostic(ctx, input, dependencies) {
8180
8392
  function compact$2(value) {
8181
8393
  return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
8182
8394
  }
8183
- const CONTROL_PANEL$1 = "control-panel";
8184
- const OBJECT_OUTPUT$2 = { type: "object", additionalProperties: true };
8395
+ const CONTROL_PANEL$2 = "control-panel";
8396
+ const OBJECT_OUTPUT$6 = { type: "object", additionalProperties: true };
8397
+ const LOG_LEVELS = ["error", "warning", "info", "debug", "trace"];
8185
8398
  function createLogModule(dependencies = {}) {
8186
8399
  return {
8187
8400
  name: "log",
8188
- summary: "Query, follow, and export redacted system logs",
8189
- commands: [queryCommand(), tailCommand(dependencies), exportCommand(dependencies)]
8401
+ summary: "List services, query, follow, and export redacted system logs",
8402
+ commands: [
8403
+ servicesCommand(),
8404
+ queryCommand(),
8405
+ tailCommand(dependencies),
8406
+ exportCommand(dependencies)
8407
+ ]
8190
8408
  };
8191
8409
  }
8192
- function queryCommand() {
8410
+ function servicesCommand() {
8193
8411
  return {
8194
- verb: "query",
8195
- summary: "Query structured redacted log entries",
8196
- options: [
8197
- ...filterOptions(false),
8198
- {
8199
- name: "direction",
8200
- description: "Page direction",
8201
- type: "string",
8412
+ verb: "services",
8413
+ summary: "List the service IDs that have system logs",
8414
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
8415
+ outputSchema: {
8416
+ type: "object",
8417
+ properties: { services: { type: "array", items: OBJECT_OUTPUT$6 } },
8418
+ required: ["services"],
8419
+ additionalProperties: false
8420
+ },
8421
+ resultSchemaVersion: 1,
8422
+ access: { mode: "fixed", level: "read" },
8423
+ asyncMode: "sync",
8424
+ requiresSession: true,
8425
+ examples: ["buckyos log services"],
8426
+ handler: async (ctx) => {
8427
+ const response = expectObject$4(
8428
+ await callService(ctx, CONTROL_PANEL$2, "system.logs.list", {}),
8429
+ "Control Panel log service list"
8430
+ );
8431
+ if (!Array.isArray(response.services))
8432
+ invalidResponse$2("log service list");
8433
+ return { services: response.services };
8434
+ }
8435
+ };
8436
+ }
8437
+ function queryCommand() {
8438
+ return {
8439
+ verb: "query",
8440
+ summary: "Query structured redacted log entries",
8441
+ options: [
8442
+ ...filterOptions(false),
8443
+ {
8444
+ name: "direction",
8445
+ description: "Page direction",
8446
+ type: "string",
8202
8447
  enum: ["forward", "backward"]
8203
8448
  },
8204
8449
  { name: "cursor", description: "Opaque page cursor", type: "string" },
@@ -8217,12 +8462,12 @@ function queryCommand() {
8217
8462
  examples: ["buckyos log query --service scheduler --level error --limit 100"],
8218
8463
  handler: async (ctx, input) => {
8219
8464
  const params = normalizeFilter(input, true);
8220
- const response = expectObject(
8221
- await callService(ctx, CONTROL_PANEL$1, "system.logs.query", params),
8465
+ const response = expectObject$4(
8466
+ await callService(ctx, CONTROL_PANEL$2, "system.logs.query", params),
8222
8467
  "Control Panel log query response"
8223
8468
  );
8224
8469
  if (!Array.isArray(response.entries))
8225
- invalidResponse$1("log query entries");
8470
+ invalidResponse$2("log query entries");
8226
8471
  return { items: response.entries, next_cursor: response.nextCursor ?? null };
8227
8472
  }
8228
8473
  };
@@ -8242,7 +8487,7 @@ function tailCommand(dependencies) {
8242
8487
  }
8243
8488
  ],
8244
8489
  inputSchema: filterSchema({ from: { type: "string", enum: ["start", "end"] } }),
8245
- outputSchema: OBJECT_OUTPUT$2,
8490
+ outputSchema: OBJECT_OUTPUT$6,
8246
8491
  resultSchemaVersion: 1,
8247
8492
  access: { mode: "fixed", level: "read" },
8248
8493
  asyncMode: "stream",
@@ -8258,8 +8503,8 @@ function tailCommand(dependencies) {
8258
8503
  const remaining = (ctx.deadline ?? Date.now()) - Date.now();
8259
8504
  if (remaining <= 0)
8260
8505
  throw timeoutError();
8261
- const response = expectObject(
8262
- await callService(ctx, CONTROL_PANEL$1, "system.logs.tail", {
8506
+ const response = expectObject$4(
8507
+ await callService(ctx, CONTROL_PANEL$2, "system.logs.tail", {
8263
8508
  ...params,
8264
8509
  cursor,
8265
8510
  from: inputString(input, "from") ?? "end",
@@ -8268,7 +8513,7 @@ function tailCommand(dependencies) {
8268
8513
  "Control Panel log tail response"
8269
8514
  );
8270
8515
  if (!Array.isArray(response.entries))
8271
- invalidResponse$1("log tail entries");
8516
+ invalidResponse$2("log tail entries");
8272
8517
  for (const entry of response.entries) {
8273
8518
  await ctx.io.stdout(`${JSON.stringify({
8274
8519
  schema_version: 1,
@@ -8277,7 +8522,7 @@ function tailCommand(dependencies) {
8277
8522
  })}
8278
8523
  `);
8279
8524
  }
8280
- cursor = expectString(response.nextCursor, "log tail nextCursor");
8525
+ cursor = expectString$2(response.nextCursor, "log tail nextCursor");
8281
8526
  await sleep(
8282
8527
  Math.min(500, Math.max(1, (ctx.deadline ?? Date.now()) - Date.now())),
8283
8528
  ctx.signal
@@ -8298,7 +8543,7 @@ function exportCommand(dependencies) {
8298
8543
  ...filterSchema({ path: { type: "string", minLength: 1 } }),
8299
8544
  required: ["path"]
8300
8545
  },
8301
- outputSchema: OBJECT_OUTPUT$2,
8546
+ outputSchema: OBJECT_OUTPUT$6,
8302
8547
  resultSchemaVersion: 1,
8303
8548
  access: { mode: "fixed", level: "read" },
8304
8549
  asyncMode: "sync",
@@ -8317,8 +8562,8 @@ function exportCommand(dependencies) {
8317
8562
  "log export requires a since or until time boundary"
8318
8563
  );
8319
8564
  }
8320
- const response = expectObject(
8321
- await callService(ctx, CONTROL_PANEL$1, "system.logs.download", {
8565
+ const response = expectObject$4(
8566
+ await callService(ctx, CONTROL_PANEL$2, "system.logs.download", {
8322
8567
  ...params,
8323
8568
  mode: "filtered"
8324
8569
  }),
@@ -8326,8 +8571,8 @@ function exportCommand(dependencies) {
8326
8571
  );
8327
8572
  const downloaded = await downloadArtifact(
8328
8573
  ctx,
8329
- CONTROL_PANEL$1,
8330
- expectString(response.url, "log export url"),
8574
+ CONTROL_PANEL$2,
8575
+ expectString$2(response.url, "log export url"),
8331
8576
  requiredInputString(input, "path"),
8332
8577
  dependencies.download
8333
8578
  );
@@ -8340,7 +8585,7 @@ function filterOptions(plural) {
8340
8585
  {
8341
8586
  name: plural ? "services" : "service",
8342
8587
  property: plural ? "services" : "service",
8343
- description: plural ? "Comma-separated service IDs" : "Service ID",
8588
+ description: plural ? "Comma-separated service IDs (buckyos log services)" : "Service ID (buckyos log services)",
8344
8589
  type: "string",
8345
8590
  required: true
8346
8591
  },
@@ -8349,7 +8594,11 @@ function filterOptions(plural) {
8349
8594
  description: "Exact filename in the service log directory",
8350
8595
  type: "string"
8351
8596
  },
8352
- { name: "level", description: "Exact normalized log level", type: "string" },
8597
+ {
8598
+ name: "level",
8599
+ description: `Log level: ${LOG_LEVELS.join(", ")} (warn = warning)`,
8600
+ type: "string"
8601
+ },
8353
8602
  { name: "keyword", description: "Case-insensitive content filter", type: "string" },
8354
8603
  { name: "since", description: "RFC 3339 lower time boundary", type: "string" },
8355
8604
  { name: "until", description: "RFC 3339 upper time boundary", type: "string" }
@@ -8382,7 +8631,7 @@ function normalizeFilter(input, withPage) {
8382
8631
  return compact$1({
8383
8632
  services,
8384
8633
  file: inputString(input, "file"),
8385
- level: inputString(input, "level")?.toLowerCase(),
8634
+ level: normalizeLevel(inputString(input, "level")),
8386
8635
  keyword: inputString(input, "keyword"),
8387
8636
  since: normalizeLogTime(input, "since"),
8388
8637
  until: normalizeLogTime(input, "until"),
@@ -8391,6 +8640,18 @@ function normalizeFilter(input, withPage) {
8391
8640
  limit: withPage ? limit : void 0
8392
8641
  });
8393
8642
  }
8643
+ function normalizeLevel(value) {
8644
+ if (!value)
8645
+ return void 0;
8646
+ const level = value.toLowerCase() === "warn" ? "warning" : value.toLowerCase();
8647
+ if (!LOG_LEVELS.includes(level)) {
8648
+ throw new UsageError(
8649
+ "INVALID_ARGUMENT",
8650
+ `level must be one of ${LOG_LEVELS.join(", ")} (warn = warning)`
8651
+ );
8652
+ }
8653
+ return level;
8654
+ }
8394
8655
  function normalizeLogTime(input, key) {
8395
8656
  const value = inputString(input, key);
8396
8657
  if (!value)
@@ -8411,7 +8672,7 @@ function pageSchema$1() {
8411
8672
  function compact$1(value) {
8412
8673
  return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
8413
8674
  }
8414
- function invalidResponse$1(label) {
8675
+ function invalidResponse$2(label) {
8415
8676
  throw new ToolError("INVALID_SERVICE_RESPONSE", `${label} is invalid`);
8416
8677
  }
8417
8678
  function timeoutError() {
@@ -8433,16 +8694,16 @@ function abortableSleep(milliseconds, signal) {
8433
8694
  });
8434
8695
  }
8435
8696
  const TASK_MANAGER = "task-manager";
8436
- const CONTROL_PANEL = "control-panel";
8437
- const OBJECT_OUTPUT$1 = { type: "object", additionalProperties: true };
8697
+ const CONTROL_PANEL$1 = "control-panel";
8698
+ const OBJECT_OUTPUT$5 = { type: "object", additionalProperties: true };
8438
8699
  function createTaskModule() {
8439
8700
  return {
8440
8701
  name: "task",
8441
8702
  summary: "Inspect, wait for, cancel, and retry durable Tasks",
8442
- commands: [listCommand(), getCommand(), waitCommand(), cancelCommand(), retryCommand()]
8703
+ commands: [listCommand$1(), getCommand$1(), waitCommand(), cancelCommand(), retryCommand()]
8443
8704
  };
8444
8705
  }
8445
- function listCommand() {
8706
+ function listCommand$1() {
8446
8707
  return {
8447
8708
  verb: "list",
8448
8709
  summary: "List visible Tasks",
@@ -8483,7 +8744,7 @@ function listCommand() {
8483
8744
  examples: ["buckyos task list --state running --limit 50"],
8484
8745
  handler: async (ctx, input) => {
8485
8746
  const limit = normalizeLimit(input.limit);
8486
- const response = expectObject(
8747
+ const response = expectObject$4(
8487
8748
  await callService(
8488
8749
  ctx,
8489
8750
  TASK_MANAGER,
@@ -8503,12 +8764,12 @@ function listCommand() {
8503
8764
  );
8504
8765
  const items = response.tasks;
8505
8766
  if (!Array.isArray(items))
8506
- invalidResponse("list_tasks.tasks");
8767
+ invalidResponse$1("list_tasks.tasks");
8507
8768
  return { items, next_cursor: response.next_cursor ?? null };
8508
8769
  }
8509
8770
  };
8510
8771
  }
8511
- function getCommand() {
8772
+ function getCommand$1() {
8512
8773
  return {
8513
8774
  verb: "get",
8514
8775
  summary: "Get one Task snapshot and its direct children",
@@ -8537,7 +8798,7 @@ function getCommand() {
8537
8798
  required: ["task_id"],
8538
8799
  additionalProperties: false
8539
8800
  },
8540
- outputSchema: OBJECT_OUTPUT$1,
8801
+ outputSchema: OBJECT_OUTPUT$5,
8541
8802
  resultSchemaVersion: 1,
8542
8803
  access: { mode: "fixed", level: "read" },
8543
8804
  asyncMode: "sync",
@@ -8558,12 +8819,12 @@ function getCommand() {
8558
8819
  })
8559
8820
  )
8560
8821
  ]);
8561
- const taskEnvelope = expectObject(taskResponse, "TaskManager get_task response");
8562
- const childrenEnvelope = expectObject(childrenResponse, "TaskManager get_subtasks response");
8822
+ const taskEnvelope = expectObject$4(taskResponse, "TaskManager get_task response");
8823
+ const childrenEnvelope = expectObject$4(childrenResponse, "TaskManager get_subtasks response");
8563
8824
  if (!Array.isArray(childrenEnvelope.tasks))
8564
- invalidResponse("get_subtasks.tasks");
8825
+ invalidResponse$1("get_subtasks.tasks");
8565
8826
  return {
8566
- task: expectObject(taskEnvelope.task ?? taskEnvelope, "TaskManager task"),
8827
+ task: expectObject$4(taskEnvelope.task ?? taskEnvelope, "TaskManager task"),
8567
8828
  children: {
8568
8829
  items: childrenEnvelope.tasks,
8569
8830
  next_cursor: childrenEnvelope.next_cursor ?? null
@@ -8578,7 +8839,7 @@ function waitCommand() {
8578
8839
  summary: "Stream changes until a Task becomes terminal",
8579
8840
  positionals: [{ name: "task_id", description: "Opaque Task ID", required: true }],
8580
8841
  inputSchema: taskIdSchema(),
8581
- outputSchema: OBJECT_OUTPUT$1,
8842
+ outputSchema: OBJECT_OUTPUT$5,
8582
8843
  resultSchemaVersion: 1,
8583
8844
  access: { mode: "fixed", level: "read" },
8584
8845
  asyncMode: "stream",
@@ -8629,7 +8890,7 @@ function cancelCommand() {
8629
8890
  required: ["task_id"],
8630
8891
  additionalProperties: false
8631
8892
  },
8632
- outputSchema: OBJECT_OUTPUT$1,
8893
+ outputSchema: OBJECT_OUTPUT$5,
8633
8894
  resultSchemaVersion: 1,
8634
8895
  access: { mode: "fixed", level: "write" },
8635
8896
  asyncMode: "sync",
@@ -8672,7 +8933,7 @@ function retryCommand() {
8672
8933
  required: ["task_id"],
8673
8934
  additionalProperties: false
8674
8935
  },
8675
- outputSchema: OBJECT_OUTPUT$1,
8936
+ outputSchema: OBJECT_OUTPUT$5,
8676
8937
  resultSchemaVersion: 1,
8677
8938
  access: { mode: "fixed", level: "write" },
8678
8939
  asyncMode: "either",
@@ -8680,24 +8941,24 @@ function retryCommand() {
8680
8941
  examples: ["buckyos --idempotency-key retry-42 task retry t-0123456789abcdef0123456789abcdef"],
8681
8942
  handler: async (ctx, input) => {
8682
8943
  const taskId = requiredInputString(input, "task_id");
8683
- const oldEnvelope = expectObject(
8944
+ const oldEnvelope = expectObject$4(
8684
8945
  await callService(ctx, TASK_MANAGER, "get_task", { task_id: taskId }),
8685
8946
  "TaskManager get_task response"
8686
8947
  );
8687
- const oldTask = expectObject(oldEnvelope.task ?? oldEnvelope, "TaskManager task");
8948
+ const oldTask = expectObject$4(oldEnvelope.task ?? oldEnvelope, "TaskManager task");
8688
8949
  if (oldTask.phase !== "Terminal" || oldTask.outcome !== "Failed") {
8689
8950
  throw new UsageError("TASK_NOT_RETRYABLE", "only a terminal failed Task can be retried");
8690
8951
  }
8691
- const response = expectObject(
8692
- await callService(ctx, CONTROL_PANEL, "task.retry", {
8952
+ const response = expectObject$4(
8953
+ await callService(ctx, CONTROL_PANEL$1, "task.retry", {
8693
8954
  task_id: taskId,
8694
8955
  idempotency_key: ctx.idempotencyKey ?? `retry-${crypto.randomUUID()}`
8695
8956
  }),
8696
8957
  "Control Panel task.retry response"
8697
8958
  );
8698
- const retryTaskId = expectString(response.task_id, "task.retry.task_id");
8959
+ const retryTaskId = expectString$2(response.task_id, "task.retry.task_id");
8699
8960
  if (retryTaskId === taskId || response.retry_of !== taskId) {
8700
- invalidResponse("task.retry identity");
8961
+ invalidResponse$1("task.retry identity");
8701
8962
  }
8702
8963
  if (input.no_wait === true)
8703
8964
  return response;
@@ -8742,11 +9003,11 @@ function normalizeLimit(value) {
8742
9003
  function compact(value) {
8743
9004
  return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
8744
9005
  }
8745
- function invalidResponse(label) {
9006
+ function invalidResponse$1(label) {
8746
9007
  throw new ToolError("INVALID_SERVICE_RESPONSE", `${label} is invalid`, EXIT_INTERNAL);
8747
9008
  }
8748
9009
  const sdk = provisionSdk;
8749
- const OBJECT_OUTPUT = { type: "object", additionalProperties: true };
9010
+ const OBJECT_OUTPUT$4 = { type: "object", additionalProperties: true };
8750
9011
  const ROOT_OPTION = {
8751
9012
  name: "root",
8752
9013
  description: "Installed BuckyOS root on this machine (BUCKYOS_ROOT); read by status/check, written by activate",
@@ -8830,7 +9091,7 @@ function statusCommand(deps) {
8830
9091
  additionalProperties: false
8831
9092
  },
8832
9093
  outputSchema: {
8833
- ...OBJECT_OUTPUT,
9094
+ ...OBJECT_OUTPUT$4,
8834
9095
  properties: {
8835
9096
  root: { type: "string" },
8836
9097
  state: {
@@ -8868,7 +9129,7 @@ function checkCommand(deps) {
8868
9129
  additionalProperties: false
8869
9130
  },
8870
9131
  outputSchema: {
8871
- ...OBJECT_OUTPUT,
9132
+ ...OBJECT_OUTPUT$4,
8872
9133
  properties: {
8873
9134
  ready: { type: "boolean" },
8874
9135
  root: { type: "string" },
@@ -8916,7 +9177,7 @@ function activateCommand(deps) {
8916
9177
  additionalProperties: false
8917
9178
  },
8918
9179
  outputSchema: {
8919
- ...OBJECT_OUTPUT,
9180
+ ...OBJECT_OUTPUT$4,
8920
9181
  properties: {
8921
9182
  root: { type: "string" },
8922
9183
  state: { type: "string", enum: ["configured"] },
@@ -9198,6 +9459,861 @@ function inputFingerprint(input) {
9198
9459
  hash.update(new TextEncoder().encode(JSON.stringify(material)));
9199
9460
  return hash.digestHex();
9200
9461
  }
9462
+ const OBJECT_OUTPUT$3 = { type: "object", additionalProperties: true };
9463
+ const SKILL_KINDS = ["cmd", "goal"];
9464
+ const SKILLS_SUB_PKG = "agent_skills";
9465
+ const SKILL_DIRS = ["cmd_skills", "goal_skills", "tools"];
9466
+ const MAX_SKILL_PAYLOAD_BYTES = 64 * 1024 * 1024;
9467
+ const AGENT_ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
9468
+ const AGENT_OPTION = {
9469
+ name: "agent",
9470
+ property: "agent_id",
9471
+ description: "Agent ID; the Agent serves kRPC at /kapi/<agent_id>",
9472
+ type: "string",
9473
+ required: true
9474
+ };
9475
+ const KIND_OPTION = {
9476
+ name: "kind",
9477
+ description: "Skill kind",
9478
+ type: "string",
9479
+ enum: SKILL_KINDS
9480
+ };
9481
+ function createSkillModule() {
9482
+ return {
9483
+ name: "skill",
9484
+ summary: "List, install, and remove the cmd/goal skills of an Agent",
9485
+ commands: [
9486
+ {
9487
+ verb: "list",
9488
+ summary: "List the skills of an Agent",
9489
+ options: [AGENT_OPTION, KIND_OPTION],
9490
+ inputSchema: {
9491
+ type: "object",
9492
+ properties: {
9493
+ agent_id: { type: "string", minLength: 1 },
9494
+ kind: { type: "string", enum: SKILL_KINDS }
9495
+ },
9496
+ required: ["agent_id"],
9497
+ additionalProperties: false
9498
+ },
9499
+ outputSchema: OBJECT_OUTPUT$3,
9500
+ resultSchemaVersion: 1,
9501
+ access: { mode: "fixed", level: "read" },
9502
+ asyncMode: "sync",
9503
+ requiresSession: true,
9504
+ examples: [
9505
+ "buckyos skill list --agent jarvis.example.zone",
9506
+ "buckyos skill list --agent jarvis.example.zone --kind cmd"
9507
+ ],
9508
+ handler: async (ctx, input) => {
9509
+ const agentId = agentIdFrom(input);
9510
+ const kind = typeof input.kind === "string" ? input.kind : void 0;
9511
+ const skills = await listSkills(ctx, agentId, kind);
9512
+ return { agent_id: agentId, ...kind ? { kind } : {}, total: skills.length, skills };
9513
+ }
9514
+ },
9515
+ {
9516
+ verb: "install",
9517
+ summary: "Install the skills of a skill PIKG into an Agent",
9518
+ description: "Verifies the PIKG offline, requires app_type agent_skills, and sends the files of its agent_skills sub package (cmd_skills/, goal_skills/, tools/) to the Agent. Sessions created before keep their frozen manuals.",
9519
+ positionals: [{ name: "pikg_path", description: "Local skill .pikg file" }],
9520
+ options: [
9521
+ AGENT_OPTION,
9522
+ {
9523
+ name: "replace",
9524
+ description: "Replace skills of the same names from another package",
9525
+ type: "boolean"
9526
+ }
9527
+ ],
9528
+ inputSchema: {
9529
+ type: "object",
9530
+ properties: {
9531
+ pikg_path: { type: "string", minLength: 1 },
9532
+ agent_id: { type: "string", minLength: 1 },
9533
+ replace: { type: "boolean" }
9534
+ },
9535
+ required: ["pikg_path", "agent_id"],
9536
+ additionalProperties: false
9537
+ },
9538
+ outputSchema: OBJECT_OUTPUT$3,
9539
+ resultSchemaVersion: 1,
9540
+ access: { mode: "fixed", level: "write" },
9541
+ asyncMode: "sync",
9542
+ requiresSession: true,
9543
+ examples: [
9544
+ "buckyos skill install ./dapp_dist/hello-skills-0.1.0.pikg --agent jarvis.example.zone",
9545
+ "buckyos skill install ./hello-skills-0.2.0.pikg --agent jarvis.example.zone --replace"
9546
+ ],
9547
+ handler: async (ctx, input) => await installSkills(ctx, input)
9548
+ },
9549
+ {
9550
+ verb: "remove",
9551
+ summary: "Remove an installed skill from an Agent",
9552
+ description: "Only installed skills can be removed. Without --kind the kind is looked up by name.",
9553
+ positionals: [{ name: "name", description: "Skill name" }],
9554
+ options: [AGENT_OPTION, KIND_OPTION],
9555
+ inputSchema: {
9556
+ type: "object",
9557
+ properties: {
9558
+ name: { type: "string", minLength: 1 },
9559
+ agent_id: { type: "string", minLength: 1 },
9560
+ kind: { type: "string", enum: SKILL_KINDS }
9561
+ },
9562
+ required: ["name", "agent_id"],
9563
+ additionalProperties: false
9564
+ },
9565
+ outputSchema: OBJECT_OUTPUT$3,
9566
+ resultSchemaVersion: 1,
9567
+ access: { mode: "fixed", level: "destructive" },
9568
+ asyncMode: "sync",
9569
+ requiresSession: true,
9570
+ examples: ["buckyos --yes skill remove hello --agent jarvis.example.zone --kind cmd"],
9571
+ handler: async (ctx, input) => await removeSkill(ctx, input)
9572
+ }
9573
+ ]
9574
+ };
9575
+ }
9576
+ async function installSkills(ctx, input) {
9577
+ const agentId = agentIdFrom(input);
9578
+ const raw = requiredInputString(input, "pikg_path");
9579
+ const path = getHost().path.isAbsolute(raw) ? getHost().path.resolve(raw) : getHost().path.resolve(ctx.cwd, raw);
9580
+ const inspection = await inspectPikg(path);
9581
+ if (inspection.app.app_type !== SKILLS_SUB_PKG) {
9582
+ throw new UsageError(
9583
+ "NOT_A_SKILL_PACKAGE",
9584
+ `PIKG app_type is ${inspection.app.app_type}; a skill package has app_type ${SKILLS_SUB_PKG} (buckyos pikg init --kind agent-skills)`
9585
+ );
9586
+ }
9587
+ const payload = inspection.subpackages.find((item) => item.key === SKILLS_SUB_PKG)?.payload;
9588
+ const archive = await openZip(path);
9589
+ const bytes = await readZipEntry(
9590
+ archive,
9591
+ archive.byName.get(payload.path),
9592
+ MAX_SKILL_PAYLOAD_BYTES
9593
+ );
9594
+ if (`sha256:${sha256Bytes(bytes)}` !== payload.digest) {
9595
+ throw new ToolError("INVALID_PACKAGE", "PIKG changed after it was verified");
9596
+ }
9597
+ const files = {};
9598
+ const ignored = [];
9599
+ for (const entry of await readTarGz(bytes, MAX_SKILL_PAYLOAD_BYTES)) {
9600
+ if (!SKILL_DIRS.includes(entry.path.split("/")[0])) {
9601
+ ignored.push(entry.path);
9602
+ continue;
9603
+ }
9604
+ files[entry.path] = { content: base64(entry.bytes), executable: entry.executable };
9605
+ }
9606
+ const result = await callService(ctx, agentId, "skills.install", {
9607
+ package: {
9608
+ package: inspection.app.name,
9609
+ version: inspection.app.version,
9610
+ pikg_digest: inspection.pikg_digest,
9611
+ files
9612
+ },
9613
+ replace: input.replace === true
9614
+ });
9615
+ return {
9616
+ agent_id: agentId,
9617
+ pikg_path: inspection.pikg_path,
9618
+ pikg_digest: inspection.pikg_digest,
9619
+ ...expectObject(result, "skills.install"),
9620
+ ...ignored.length ? { ignored_files: ignored } : {}
9621
+ };
9622
+ }
9623
+ async function removeSkill(ctx, input) {
9624
+ const agentId = agentIdFrom(input);
9625
+ const name = requiredInputString(input, "name");
9626
+ let kind = typeof input.kind === "string" ? input.kind : void 0;
9627
+ if (!kind) {
9628
+ const kinds = (await listSkills(ctx, agentId)).filter((skill) => skill.name === name).map((skill) => String(skill.kind));
9629
+ if (kinds.length === 0) {
9630
+ throw new ToolError("RESOURCE_NOT_FOUND", `Agent ${agentId} has no skill named ${name}`);
9631
+ }
9632
+ if (kinds.length > 1) {
9633
+ throw new UsageError("AMBIGUOUS_SKILL", `${name} is both a cmd and a goal skill; use --kind`);
9634
+ }
9635
+ kind = kinds[0];
9636
+ }
9637
+ if (!ctx.confirmed) {
9638
+ if (ctx.config.nonInteractive || !ctx.io.inputIsTerminal) {
9639
+ throw new ToolError(
9640
+ "CONFIRMATION_REQUIRED",
9641
+ "skill remove requires --yes in non-interactive execution",
9642
+ EXIT_PERMISSION
9643
+ );
9644
+ }
9645
+ const answer = (await ctx.io.prompt(`Remove ${kind} skill ${name} from ${agentId}? [y/N] `))?.trim().toLowerCase();
9646
+ if (answer !== "y" && answer !== "yes") {
9647
+ throw new ToolError("CONFIRMATION_DECLINED", "skill remove was declined", EXIT_PERMISSION);
9648
+ }
9649
+ }
9650
+ const removed = await callService(ctx, agentId, "skills.remove", { kind, name });
9651
+ return { agent_id: agentId, removed: expectObject(removed, "skills.remove") };
9652
+ }
9653
+ async function listSkills(ctx, agentId, kind) {
9654
+ const skills = await callService(ctx, agentId, "skills.list", kind ? { kind } : {});
9655
+ if (!Array.isArray(skills))
9656
+ invalidResponse("skills.list");
9657
+ return skills.map((skill) => expectObject(skill, "skills.list"));
9658
+ }
9659
+ function agentIdFrom(input) {
9660
+ const agentId = requiredInputString(input, "agent_id");
9661
+ if (!AGENT_ID.test(agentId)) {
9662
+ throw new UsageError("INVALID_AGENT_ID", `invalid Agent ID: ${agentId}`);
9663
+ }
9664
+ return agentId;
9665
+ }
9666
+ function expectObject(value, method) {
9667
+ if (!value || typeof value !== "object" || Array.isArray(value))
9668
+ invalidResponse(method);
9669
+ return value;
9670
+ }
9671
+ function invalidResponse(method) {
9672
+ throw new ToolError(
9673
+ "INVALID_SERVICE_RESPONSE",
9674
+ `Agent returned an invalid response for ${method}`,
9675
+ EXIT_INTERNAL
9676
+ );
9677
+ }
9678
+ function base64(bytes) {
9679
+ let binary = "";
9680
+ for (let index = 0; index < bytes.length; index += 32768) {
9681
+ binary += String.fromCharCode(...bytes.subarray(index, index + 32768));
9682
+ }
9683
+ return btoa(binary);
9684
+ }
9685
+ const CONTROL_PANEL = "control-panel";
9686
+ const OBJECT_OUTPUT$2 = { type: "object", additionalProperties: true };
9687
+ const AGENT_POSITIONAL = {
9688
+ name: "agent_id",
9689
+ description: "Agent ID as `agent list` prints it (raw host name, e.g. jarvis.example.zone)"
9690
+ };
9691
+ const AGENT_INPUT = {
9692
+ type: "object",
9693
+ properties: { agent_id: { type: "string", minLength: 1 } },
9694
+ required: ["agent_id"],
9695
+ additionalProperties: false
9696
+ };
9697
+ const PROFILE_FIELDS = ["display_name", "bio"];
9698
+ function createAgentModule() {
9699
+ return {
9700
+ name: "agent",
9701
+ summary: "List Agents and read or change their profiles",
9702
+ commands: [
9703
+ {
9704
+ verb: "list",
9705
+ summary: "List the Agents visible to the caller",
9706
+ description: "Owners see their own Agents; admins see every Agent in the Zone.",
9707
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
9708
+ outputSchema: {
9709
+ type: "object",
9710
+ properties: { agents: { type: "array", items: OBJECT_OUTPUT$2 } },
9711
+ required: ["agents"],
9712
+ additionalProperties: false
9713
+ },
9714
+ resultSchemaVersion: 1,
9715
+ access: { mode: "fixed", level: "read" },
9716
+ asyncMode: "sync",
9717
+ requiresSession: true,
9718
+ examples: ["buckyos agent list"],
9719
+ handler: async (ctx) => {
9720
+ const response = await callAgent(ctx, "agent.list", {});
9721
+ if (!Array.isArray(response.agents)) {
9722
+ throw new ToolError(
9723
+ "INVALID_SERVICE_RESPONSE",
9724
+ "agent.list agents must be an array",
9725
+ EXIT_INTERNAL
9726
+ );
9727
+ }
9728
+ return { agents: response.agents };
9729
+ }
9730
+ },
9731
+ {
9732
+ verb: "get",
9733
+ summary: "Get one Agent: profile, settings, install state, template, and runtime",
9734
+ positionals: [AGENT_POSITIONAL],
9735
+ inputSchema: AGENT_INPUT,
9736
+ outputSchema: OBJECT_OUTPUT$2,
9737
+ resultSchemaVersion: 1,
9738
+ access: { mode: "fixed", level: "read" },
9739
+ asyncMode: "sync",
9740
+ requiresSession: true,
9741
+ examples: ["buckyos agent get jarvis.example.zone"],
9742
+ handler: async (ctx, input) => await callAgent(ctx, "agent.get", { agent_id: requiredInputString(input, "agent_id") })
9743
+ },
9744
+ {
9745
+ verb: "profile-get",
9746
+ summary: "Get the public profile (display name, bio, avatar) of an Agent",
9747
+ positionals: [AGENT_POSITIONAL],
9748
+ inputSchema: AGENT_INPUT,
9749
+ outputSchema: OBJECT_OUTPUT$2,
9750
+ resultSchemaVersion: 1,
9751
+ access: { mode: "fixed", level: "read" },
9752
+ asyncMode: "sync",
9753
+ requiresSession: true,
9754
+ examples: ["buckyos agent profile-get jarvis.example.zone"],
9755
+ handler: async (ctx, input) => {
9756
+ const agentId = requiredInputString(input, "agent_id");
9757
+ return {
9758
+ agent_id: agentId,
9759
+ ...await callAgent(ctx, "agent.profile.get", { agent_id: agentId })
9760
+ };
9761
+ }
9762
+ },
9763
+ {
9764
+ verb: "profile-set",
9765
+ summary: "Change the display name or bio of an Agent",
9766
+ description: "Only the given fields change; an empty value clears the field. Returns the profile before and after the change, and Message Center reloads the new name.",
9767
+ positionals: [AGENT_POSITIONAL],
9768
+ options: [
9769
+ {
9770
+ name: "display-name",
9771
+ description: "New display name; empty clears it",
9772
+ type: "string"
9773
+ },
9774
+ { name: "bio", description: "New bio; empty clears it", type: "string" }
9775
+ ],
9776
+ inputSchema: {
9777
+ type: "object",
9778
+ properties: {
9779
+ agent_id: { type: "string", minLength: 1 },
9780
+ display_name: { type: "string" },
9781
+ bio: { type: "string" }
9782
+ },
9783
+ required: ["agent_id"],
9784
+ additionalProperties: false
9785
+ },
9786
+ outputSchema: {
9787
+ type: "object",
9788
+ properties: {
9789
+ agent_id: { type: "string" },
9790
+ before: OBJECT_OUTPUT$2,
9791
+ profile: OBJECT_OUTPUT$2
9792
+ },
9793
+ required: ["agent_id", "before", "profile"],
9794
+ additionalProperties: false
9795
+ },
9796
+ resultSchemaVersion: 1,
9797
+ access: { mode: "fixed", level: "write" },
9798
+ asyncMode: "sync",
9799
+ requiresSession: true,
9800
+ examples: [
9801
+ "buckyos agent profile-set jarvis.example.zone --display-name 'Jarvis'",
9802
+ "buckyos agent profile-set jarvis.example.zone --bio ''"
9803
+ ],
9804
+ handler: async (ctx, input) => {
9805
+ const agentId = requiredInputString(input, "agent_id");
9806
+ const changes = Object.fromEntries(
9807
+ PROFILE_FIELDS.filter((field) => typeof input[field] === "string").map((field) => [field, input[field]])
9808
+ );
9809
+ if (Object.keys(changes).length === 0) {
9810
+ throw new UsageError("INVALID_ARGUMENT", "give --display-name or --bio");
9811
+ }
9812
+ const before = await callAgent(ctx, "agent.profile.get", { agent_id: agentId });
9813
+ const after = await callAgent(ctx, "agent.profile.set", { agent_id: agentId, ...changes });
9814
+ return {
9815
+ agent_id: agentId,
9816
+ before: expectObject$4(before.profile, "agent.profile.get profile"),
9817
+ profile: expectObject$4(after.profile, "agent.profile.set profile")
9818
+ };
9819
+ }
9820
+ }
9821
+ ]
9822
+ };
9823
+ }
9824
+ async function callAgent(ctx, method, params) {
9825
+ try {
9826
+ return expectObject$4(await callService(ctx, CONTROL_PANEL, method, params), method);
9827
+ } catch (error) {
9828
+ const message = error instanceof Error ? error.message : String(error);
9829
+ if (message.includes("agent_not_found")) {
9830
+ throw new ToolError("RESOURCE_NOT_FOUND", `Agent not found or not yours: ${params.agent_id}`);
9831
+ }
9832
+ throw error;
9833
+ }
9834
+ }
9835
+ const AICC = "aicc";
9836
+ const OBJECT_OUTPUT$1 = { type: "object", additionalProperties: true };
9837
+ const EMPTY_INPUT = { type: "object", properties: {}, additionalProperties: false };
9838
+ const RANGES = ["last1d", "last7d", "last30d"];
9839
+ const GROUPS = [
9840
+ "provider_instance_name",
9841
+ "provider_model",
9842
+ "request_model",
9843
+ "method",
9844
+ "capability",
9845
+ "caller_app_id",
9846
+ "user_id",
9847
+ "tenant_id"
9848
+ ];
9849
+ function createAiModule() {
9850
+ return {
9851
+ name: "ai",
9852
+ summary: "Read AI provider, routing, and usage state of the AICC service",
9853
+ commands: [
9854
+ readCommand({
9855
+ verb: "providers",
9856
+ summary: "List configured AI provider instances with auth, health, and model inventory",
9857
+ method: "provider.list",
9858
+ description: "Credentials are reported only as configured/kind; secrets are never returned."
9859
+ }),
9860
+ readCommand({
9861
+ verb: "routing",
9862
+ summary: "Get the AICC routing overlay and its settings revision",
9863
+ method: "routing.get",
9864
+ description: "An empty routing object means the default routing of the model catalog."
9865
+ }),
9866
+ usageCommand()
9867
+ ]
9868
+ };
9869
+ }
9870
+ function readCommand(options) {
9871
+ return {
9872
+ verb: options.verb,
9873
+ summary: options.summary,
9874
+ description: options.description,
9875
+ inputSchema: EMPTY_INPUT,
9876
+ outputSchema: OBJECT_OUTPUT$1,
9877
+ resultSchemaVersion: 1,
9878
+ access: { mode: "fixed", level: "read" },
9879
+ asyncMode: "sync",
9880
+ requiresSession: true,
9881
+ examples: [`buckyos ai ${options.verb}`],
9882
+ handler: async (ctx) => expectObject$4(await callService(ctx, AICC, options.method, {}), options.method)
9883
+ };
9884
+ }
9885
+ function usageCommand() {
9886
+ return {
9887
+ verb: "usage",
9888
+ summary: "Aggregate the caller's AI usage: requests, tokens, and cost",
9889
+ description: "Scoped to the caller's own user (a device identity sees only its own calls, not the Zone total). Without --since the range defaults to last7d; --until defaults to now.",
9890
+ options: [
9891
+ {
9892
+ name: "range",
9893
+ description: "last1d, last7d (default), or last30d",
9894
+ type: "string",
9895
+ enum: RANGES
9896
+ },
9897
+ { name: "since", description: "RFC 3339 or Unix ms lower bound", type: "string" },
9898
+ { name: "until", description: "RFC 3339 or Unix ms upper bound", type: "string" },
9899
+ {
9900
+ name: "group-by",
9901
+ description: `Comma-separated: ${GROUPS.join(", ")}`,
9902
+ type: "string"
9903
+ },
9904
+ {
9905
+ name: "bucket",
9906
+ description: "Time buckets: hour or day",
9907
+ type: "string",
9908
+ enum: ["hour", "day"]
9909
+ },
9910
+ { name: "events", description: "Also return the individual usage events", type: "boolean" },
9911
+ { name: "limit", description: "Event page size", type: "integer" },
9912
+ { name: "cursor", description: "Opaque event page cursor", type: "string" }
9913
+ ],
9914
+ inputSchema: {
9915
+ type: "object",
9916
+ properties: {
9917
+ range: { type: "string", enum: RANGES },
9918
+ since: { type: "string", minLength: 1 },
9919
+ until: { type: "string", minLength: 1 },
9920
+ group_by: { type: "string", minLength: 1 },
9921
+ bucket: { type: "string", enum: ["hour", "day"] },
9922
+ events: { type: "boolean" },
9923
+ limit: { type: "integer", minimum: 1 },
9924
+ cursor: { type: "string", minLength: 1 }
9925
+ },
9926
+ additionalProperties: false
9927
+ },
9928
+ outputSchema: OBJECT_OUTPUT$1,
9929
+ resultSchemaVersion: 1,
9930
+ access: { mode: "fixed", level: "read" },
9931
+ asyncMode: "sync",
9932
+ requiresSession: true,
9933
+ examples: [
9934
+ "buckyos ai usage --range last1d --group-by provider_instance_name,provider_model",
9935
+ "buckyos ai usage --since 2026-10-01T00:00:00Z --bucket day"
9936
+ ],
9937
+ handler: async (ctx, input) => {
9938
+ const groupBy = splitServices(input.group_by);
9939
+ const unknown = groupBy.filter((group) => !GROUPS.includes(group));
9940
+ if (unknown.length > 0) {
9941
+ throw new UsageError(
9942
+ "INVALID_ARGUMENT",
9943
+ `unknown group-by ${unknown.join(", ")}; use ${GROUPS.join(", ")}`
9944
+ );
9945
+ }
9946
+ return expectObject$4(
9947
+ await callService(ctx, AICC, "usage.query", {
9948
+ time_range: timeRange(input),
9949
+ ...groupBy.length > 0 ? { group_by: groupBy } : {},
9950
+ ...input.bucket ? { time_bucket: input.bucket } : {},
9951
+ output_mode: input.events === true ? "summary_and_events" : "summary",
9952
+ ...input.limit !== void 0 ? { limit: input.limit } : {},
9953
+ ...inputString(input, "cursor") ? { cursor: inputString(input, "cursor") } : {}
9954
+ }),
9955
+ "usage.query"
9956
+ );
9957
+ }
9958
+ };
9959
+ }
9960
+ function timeRange(input) {
9961
+ const since = parseTimestamp(input.since, "since");
9962
+ const until = parseTimestamp(input.until, "until");
9963
+ if (since === void 0) {
9964
+ if (until !== void 0)
9965
+ throw new UsageError("INVALID_ARGUMENT", "--until requires --since");
9966
+ return { kind: inputString(input, "range") ?? "last7d" };
9967
+ }
9968
+ if (input.range !== void 0) {
9969
+ throw new UsageError("ARGUMENT_CONFLICT", "--range cannot be combined with --since");
9970
+ }
9971
+ return { kind: "explicit", start_time_ms: since, end_time_ms: until ?? Date.now() };
9972
+ }
9973
+ const OBJECT_OUTPUT = { type: "object", additionalProperties: true };
9974
+ const DAY_MS = 864e5;
9975
+ const EXPIRES_HELP = "1d, 7d (default), 30d, none, or an RFC 3339 time";
9976
+ function createShareModule() {
9977
+ return {
9978
+ name: "share",
9979
+ summary: "Share files and folders as links, and manage what you have shared",
9980
+ commands: [
9981
+ createCommand(),
9982
+ listCommand(),
9983
+ getCommand(),
9984
+ updateCommand(),
9985
+ stopCommand(),
9986
+ statsCommand()
9987
+ ]
9988
+ };
9989
+ }
9990
+ async function openNfsp(ctx) {
9991
+ const session = ctx.session;
9992
+ if (!session)
9993
+ throw new ToolError("AUTH_REQUIRED", "authenticated session is required", 3);
9994
+ const token = (await session.ensureValid()).token;
9995
+ const base = gatewayOrigin(ctx.connection.endpoint);
9996
+ let seq = 0;
9997
+ const post = async (method, body) => {
9998
+ const response = await fetch(`${base}/nfs/v1/${method}`, {
9999
+ method: "POST",
10000
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
10001
+ body: JSON.stringify(body),
10002
+ signal: ctx.signal
10003
+ });
10004
+ let parsed;
10005
+ try {
10006
+ parsed = await response.json();
10007
+ } catch {
10008
+ throw new ToolError("INVALID_SERVICE_RESPONSE", `file service answered HTTP ${response.status}`, EXIT_INTERNAL);
10009
+ }
10010
+ if (parsed.ok !== true) {
10011
+ const error = parsed.error ?? {};
10012
+ const reason = typeof error.reason === "string" ? error.reason.toUpperCase() : String(error.code ?? "INTERNAL");
10013
+ throw new ToolError(`SHARE_${reason}`, String(error.message ?? "share request failed"));
10014
+ }
10015
+ return expectObject$4(parsed.result, `${method} result`);
10016
+ };
10017
+ const hello = await post("hello", { args: { versions: ["nfsp/0"] } });
10018
+ const sessionId = String(hello.session ?? "");
10019
+ if (!Array.isArray(hello.features) || !hello.features.includes("share")) {
10020
+ throw new ToolError("SHARE_UNSUPPORTED", "the file service of this Zone does not support sharing");
10021
+ }
10022
+ return {
10023
+ call: (method, args, write = false) => post(method, { session: sessionId, args: { ...args, source_hint: "cli" }, ...write ? { seq: ++seq } : {} })
10024
+ };
10025
+ }
10026
+ function gatewayOrigin(endpoint) {
10027
+ const url = new URL(endpoint);
10028
+ const marker = url.pathname.indexOf("/kapi");
10029
+ url.pathname = marker >= 0 ? url.pathname.slice(0, marker) || "/" : "/";
10030
+ url.search = "";
10031
+ url.hash = "";
10032
+ return url.toString().replace(/\/$/, "");
10033
+ }
10034
+ function parseExpires(value) {
10035
+ if (value === void 0)
10036
+ return void 0;
10037
+ const text = String(value).trim().toLowerCase();
10038
+ if (text === "none" || text === "never")
10039
+ return null;
10040
+ const days = text.match(/^(\d+)d$/);
10041
+ if (days)
10042
+ return Math.floor((Date.now() + Number(days[1]) * DAY_MS) / 1e3);
10043
+ const at = parseTimestamp(value, "expires");
10044
+ if (at === void 0)
10045
+ return void 0;
10046
+ if (at <= Date.now())
10047
+ throw new UsageError("INVALID_ARGUMENT", "expires must be in the future");
10048
+ return Math.floor(at / 1e3);
10049
+ }
10050
+ function sourceLocator(path) {
10051
+ if (path.startsWith("cyfs://"))
10052
+ return { uri: path };
10053
+ return { path: path.startsWith("/") ? path : `/${path}` };
10054
+ }
10055
+ function summary(share) {
10056
+ const keep = ["share_id", "kind", "title", "status", "access", "expires_at", "url", "target_app", "delivery_state", "source_path", "revision", "created_at", "stats"];
10057
+ return Object.fromEntries(keep.filter((key) => share[key] !== void 0).map((key) => [key, share[key]]));
10058
+ }
10059
+ function createCommand() {
10060
+ return {
10061
+ verb: "create",
10062
+ summary: "Share a file or folder as a link (a snapshot of its current content)",
10063
+ positionals: [{ name: "path", description: "File or folder, e.g. /home/alice/report.pdf or cyfs:///home/alice/report.pdf", required: true }],
10064
+ options: [
10065
+ { name: "expires", description: `Link expiry: ${EXPIRES_HELP}`, type: "string" },
10066
+ { name: "password", description: "Require this password to open the link", type: "string" },
10067
+ { name: "title", description: "Title shown to visitors", type: "string" },
10068
+ { name: "no-download", property: "no_download", description: "Preview only, no download button", type: "boolean" },
10069
+ { name: "wait", description: "Wait for a large snapshot to finish", type: "boolean" }
10070
+ ],
10071
+ inputSchema: {
10072
+ type: "object",
10073
+ properties: {
10074
+ path: { type: "string", minLength: 1 },
10075
+ expires: { type: "string", minLength: 1 },
10076
+ password: { type: "string", minLength: 1 },
10077
+ title: { type: "string", minLength: 1 },
10078
+ no_download: { type: "boolean" },
10079
+ wait: { type: "boolean" }
10080
+ },
10081
+ required: ["path"],
10082
+ additionalProperties: false
10083
+ },
10084
+ outputSchema: OBJECT_OUTPUT,
10085
+ resultSchemaVersion: 1,
10086
+ access: { mode: "fixed", level: "write" },
10087
+ asyncMode: "either",
10088
+ requiresSession: true,
10089
+ examples: [
10090
+ "buckyos share create /home/alice/report.pdf",
10091
+ "buckyos share create /home/alice/photos --expires 30d --password s3cret"
10092
+ ],
10093
+ handler: async (ctx, input) => {
10094
+ const nfsp = await openNfsp(ctx);
10095
+ const expires = parseExpires(input.expires);
10096
+ const password = inputString(input, "password");
10097
+ const policy2 = {
10098
+ access: password ? "password" : "holder",
10099
+ allow_download: input.no_download !== true,
10100
+ ...password ? { password } : {},
10101
+ ...expires !== void 0 ? { expires_at: expires } : {}
10102
+ };
10103
+ let op = await nfsp.call("share.create", {
10104
+ source: sourceLocator(requiredInputString(input, "path")),
10105
+ policy: policy2,
10106
+ title: inputString(input, "title"),
10107
+ idempotency_key: ctx.idempotencyKey ?? crypto.randomUUID()
10108
+ }, true);
10109
+ while (input.wait === true && (op.state === "running" || op.state === "preparing")) {
10110
+ await new Promise((resolve2) => setTimeout(resolve2, 1e3));
10111
+ ctx.signal.throwIfAborted();
10112
+ op = await nfsp.call("share.operation", { operation_id: op.operation_id });
10113
+ }
10114
+ if (op.state === "failed" || op.state === "canceled") {
10115
+ const error = op.error ?? {};
10116
+ throw new ToolError(`SHARE_${String(error.reason ?? op.state).toUpperCase()}`, String(error.message ?? `share ${op.state}`));
10117
+ }
10118
+ return {
10119
+ operation_id: op.operation_id,
10120
+ state: op.state,
10121
+ share_id: op.share_id ?? null,
10122
+ url: op.url ?? null,
10123
+ source_changed: op.source_changed ?? false,
10124
+ ...op.share ? { share: summary(op.share) } : {}
10125
+ };
10126
+ }
10127
+ };
10128
+ }
10129
+ function listCommand() {
10130
+ return {
10131
+ verb: "list",
10132
+ summary: "List your shares",
10133
+ options: [
10134
+ { name: "kind", description: "link or app_delivery", type: "string", enum: ["link", "app_delivery"] },
10135
+ { name: "status", description: "active, stopped, expired, ...", type: "string" },
10136
+ { name: "q", description: "Search title and path", type: "string" },
10137
+ { name: "include-hidden", property: "include_hidden", description: "Include hidden shares", type: "boolean" },
10138
+ { name: "cursor", description: "Page cursor", type: "string" },
10139
+ { name: "limit", description: "Page size, at most 200", type: "integer" }
10140
+ ],
10141
+ inputSchema: {
10142
+ type: "object",
10143
+ properties: {
10144
+ kind: { type: "string", enum: ["link", "app_delivery"] },
10145
+ status: { type: "string", minLength: 1 },
10146
+ q: { type: "string", minLength: 1 },
10147
+ include_hidden: { type: "boolean" },
10148
+ cursor: { type: "string", minLength: 1 },
10149
+ limit: { type: "integer", minimum: 1 }
10150
+ },
10151
+ additionalProperties: false
10152
+ },
10153
+ outputSchema: OBJECT_OUTPUT,
10154
+ resultSchemaVersion: 1,
10155
+ access: { mode: "fixed", level: "read" },
10156
+ asyncMode: "sync",
10157
+ requiresSession: true,
10158
+ examples: ["buckyos share list --kind link --status active"],
10159
+ handler: async (ctx, input) => {
10160
+ const nfsp = await openNfsp(ctx);
10161
+ const page = await nfsp.call("share.list", {
10162
+ kind: input.kind,
10163
+ status: input.status,
10164
+ q: input.q,
10165
+ include_hidden: input.include_hidden === true,
10166
+ cursor: input.cursor,
10167
+ limit: input.limit
10168
+ });
10169
+ const items = Array.isArray(page.items) ? page.items : [];
10170
+ return { items: items.map(summary), next_cursor: page.next_cursor ?? null };
10171
+ }
10172
+ };
10173
+ }
10174
+ function getCommand() {
10175
+ return {
10176
+ verb: "get",
10177
+ summary: "Show one share: link, policy, snapshot, delivery, statistics and history",
10178
+ positionals: [{ name: "share_id", description: "Share ID (sh_…)", required: true }],
10179
+ inputSchema: {
10180
+ type: "object",
10181
+ properties: { share_id: { type: "string", minLength: 1 } },
10182
+ required: ["share_id"],
10183
+ additionalProperties: false
10184
+ },
10185
+ outputSchema: OBJECT_OUTPUT,
10186
+ resultSchemaVersion: 1,
10187
+ access: { mode: "fixed", level: "read" },
10188
+ asyncMode: "sync",
10189
+ requiresSession: true,
10190
+ examples: ["buckyos share get sh_0123456789abcdef"],
10191
+ handler: async (ctx, input) => {
10192
+ const nfsp = await openNfsp(ctx);
10193
+ return await nfsp.call("share.get", { share_id: requiredInputString(input, "share_id") });
10194
+ }
10195
+ };
10196
+ }
10197
+ function updateCommand() {
10198
+ return {
10199
+ verb: "update",
10200
+ summary: "Change a link's expiry, password, title or download setting",
10201
+ positionals: [{ name: "share_id", description: "Share ID (sh_…)", required: true }],
10202
+ options: [
10203
+ { name: "expires", description: `New expiry: ${EXPIRES_HELP}`, type: "string" },
10204
+ { name: "password", description: "Set or change the password", type: "string" },
10205
+ { name: "no-password", property: "no_password", description: "Remove the password", type: "boolean" },
10206
+ { name: "title", description: "New title", type: "string" },
10207
+ { name: "download", description: "Allow (true) or forbid (false) downloading", type: "boolean" }
10208
+ ],
10209
+ inputSchema: {
10210
+ type: "object",
10211
+ properties: {
10212
+ share_id: { type: "string", minLength: 1 },
10213
+ expires: { type: "string", minLength: 1 },
10214
+ password: { type: "string", minLength: 1 },
10215
+ no_password: { type: "boolean" },
10216
+ title: { type: "string", minLength: 1 },
10217
+ download: { type: "boolean" }
10218
+ },
10219
+ required: ["share_id"],
10220
+ additionalProperties: false
10221
+ },
10222
+ outputSchema: OBJECT_OUTPUT,
10223
+ resultSchemaVersion: 1,
10224
+ access: { mode: "fixed", level: "write" },
10225
+ asyncMode: "sync",
10226
+ requiresSession: true,
10227
+ examples: ["buckyos share update sh_0123456789abcdef --expires none", "buckyos share update sh_0123456789abcdef --password n3w"],
10228
+ handler: async (ctx, input) => {
10229
+ if (input.password !== void 0 && input.no_password === true) {
10230
+ throw new UsageError("INVALID_ARGUMENT", "use either --password or --no-password");
10231
+ }
10232
+ const changes = {};
10233
+ const expires = parseExpires(input.expires);
10234
+ if (expires !== void 0)
10235
+ changes.expires_at = expires;
10236
+ if (input.password !== void 0)
10237
+ changes.password = String(input.password);
10238
+ if (input.no_password === true)
10239
+ changes.password = null;
10240
+ if (input.title !== void 0)
10241
+ changes.title = String(input.title);
10242
+ if (input.download !== void 0)
10243
+ changes.allow_download = input.download === true;
10244
+ if (!Object.keys(changes).length)
10245
+ throw new UsageError("INVALID_ARGUMENT", "nothing to change");
10246
+ const nfsp = await openNfsp(ctx);
10247
+ const shareId = requiredInputString(input, "share_id");
10248
+ const current = await nfsp.call("share.get", { share_id: shareId });
10249
+ const result = await nfsp.call("share.update", { share_id: shareId, revision: current.revision, changes }, true);
10250
+ return { revision: result.revision, share: summary(expectObject$4(result.share, "share.update share")) };
10251
+ }
10252
+ };
10253
+ }
10254
+ function stopCommand() {
10255
+ return {
10256
+ verb: "stop",
10257
+ summary: "Stop a share: the link stops working and the kept snapshot is released",
10258
+ positionals: [{ name: "share_id", description: "Share ID (sh_…)", required: true }],
10259
+ options: [{ name: "reason", description: "Recorded in the share history", type: "string" }],
10260
+ inputSchema: {
10261
+ type: "object",
10262
+ properties: { share_id: { type: "string", minLength: 1 }, reason: { type: "string", minLength: 1 } },
10263
+ required: ["share_id"],
10264
+ additionalProperties: false
10265
+ },
10266
+ outputSchema: OBJECT_OUTPUT,
10267
+ resultSchemaVersion: 1,
10268
+ access: { mode: "fixed", level: "destructive" },
10269
+ asyncMode: "sync",
10270
+ requiresSession: true,
10271
+ examples: ['buckyos share stop sh_0123456789abcdef --reason "sent by mistake"'],
10272
+ handler: async (ctx, input) => {
10273
+ const nfsp = await openNfsp(ctx);
10274
+ const shareId = requiredInputString(input, "share_id");
10275
+ const current = await nfsp.call("share.get", { share_id: shareId });
10276
+ return await nfsp.call("share.stop", { share_id: shareId, revision: current.revision, reason: inputString(input, "reason") }, true);
10277
+ }
10278
+ };
10279
+ }
10280
+ function statsCommand() {
10281
+ return {
10282
+ verb: "stats",
10283
+ summary: "Views, downloads, traffic and visitors of one share or all of yours",
10284
+ options: [
10285
+ { name: "share-id", property: "share_id", description: "One share instead of all", type: "string" },
10286
+ { name: "days", description: "How many days back (default 30)", type: "integer" },
10287
+ { name: "granularity", description: "day or hour", type: "string", enum: ["day", "hour"] }
10288
+ ],
10289
+ inputSchema: {
10290
+ type: "object",
10291
+ properties: {
10292
+ share_id: { type: "string", minLength: 1 },
10293
+ days: { type: "integer", minimum: 1 },
10294
+ granularity: { type: "string", enum: ["day", "hour"] }
10295
+ },
10296
+ additionalProperties: false
10297
+ },
10298
+ outputSchema: OBJECT_OUTPUT,
10299
+ resultSchemaVersion: 1,
10300
+ access: { mode: "fixed", level: "read" },
10301
+ asyncMode: "sync",
10302
+ requiresSession: true,
10303
+ examples: ["buckyos share stats --days 7", "buckyos share stats --share-id sh_0123456789abcdef --granularity hour --days 2"],
10304
+ handler: async (ctx, input) => {
10305
+ const nfsp = await openNfsp(ctx);
10306
+ const to = Math.floor(Date.now() / 1e3) + 1;
10307
+ const days = typeof input.days === "number" ? input.days : 30;
10308
+ return await nfsp.call("share.stats", {
10309
+ share_id: inputString(input, "share_id"),
10310
+ from: to - days * 86400,
10311
+ to,
10312
+ granularity: input.granularity ?? "day"
10313
+ });
10314
+ }
10315
+ };
10316
+ }
9201
10317
  const VERSION = TOOL_VERSION;
9202
10318
  class BuckyOSToolApplication {
9203
10319
  #environment;
@@ -9561,6 +10677,10 @@ function createRegistry(pikgDependencies, appDependencies, logDependencies, diag
9561
10677
  registry.register(createLogModule(logDependencies));
9562
10678
  registry.register(createDiagnosticModule(diagnosticDependencies));
9563
10679
  registry.register(createProvisionModule(provisionDependencies));
10680
+ registry.register(createSkillModule());
10681
+ registry.register(createAgentModule());
10682
+ registry.register(createAiModule());
10683
+ registry.register(createShareModule());
9564
10684
  return registry;
9565
10685
  }
9566
10686
  function assertNoSessionOptions(global, command) {