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/README.md +9 -5
- package/cli/core/app.ts +8 -0
- package/cli/dist/cli.mjs +1360 -240
- package/cli/dist/cli.mjs.map +1 -1
- package/cli/modules/agent.ts +165 -0
- package/cli/modules/ai.ts +160 -0
- package/cli/modules/app.ts +86 -0
- package/cli/modules/log.ts +57 -5
- package/cli/modules/pikg.ts +14 -7
- package/cli/modules/pikg_archive.ts +83 -0
- package/cli/modules/pikg_protocol.ts +11 -1
- package/cli/modules/share.ts +356 -0
- package/cli/modules/skill.ts +256 -0
- package/cli/modules/system.ts +54 -15
- package/cli/runtime/host.ts +4 -0
- package/cli/version.ts +1 -1
- package/dist/browser.cjs +1 -1
- package/dist/browser.mjs +118 -110
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +118 -110
- package/dist/msg_center_client.d.ts +156 -5
- package/dist/msg_center_client.d.ts.map +1 -1
- package/dist/{ndm_proxy-a167f2a4.mjs → ndm_proxy-501cb1e8.mjs} +201 -109
- package/dist/ndm_proxy-501cb1e8.mjs.map +1 -0
- package/dist/ndm_proxy-68b8160c.js +13 -0
- package/dist/ndm_proxy-68b8160c.js.map +1 -0
- package/dist/nfsp.cjs +1 -1
- package/dist/nfsp.cjs.map +1 -1
- package/dist/nfsp.d.ts +300 -0
- package/dist/nfsp.d.ts.map +1 -1
- package/dist/nfsp.mjs +105 -0
- package/dist/nfsp.mjs.map +1 -1
- package/dist/node.cjs +1 -1
- package/dist/node.mjs +118 -110
- package/dist/sdk_core.d.ts +2 -2
- package/dist/sdk_core.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/ndm_proxy-28e72ddf.js +0 -13
- package/dist/ndm_proxy-28e72ddf.js.map +0 -1
- package/dist/ndm_proxy-a167f2a4.mjs.map +0 -1
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, ...
|
|
689
|
+
const { npm_files: files, ...summary2 } = manifest;
|
|
685
690
|
return {
|
|
686
|
-
...
|
|
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$
|
|
2497
|
-
const OBJECT_OUTPUT$
|
|
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$
|
|
2507
|
-
outputSchema: OBJECT_OUTPUT$
|
|
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$
|
|
2525
|
-
outputSchema: OBJECT_OUTPUT$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
|
2886
|
-
|
|
2887
|
-
|
|
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) =>
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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.
|
|
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$
|
|
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$
|
|
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:
|
|
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:
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
-
|
|
5428
|
+
`App kind (${APP_KINDS.join("/")}): `,
|
|
5238
5429
|
"kind"
|
|
5239
5430
|
);
|
|
5240
5431
|
}
|
|
5241
|
-
if (!
|
|
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
|
|
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
|
|
5481
|
+
categories: [PATH_KINDS[kind]?.category ?? "dapp"],
|
|
5291
5482
|
permissions: [],
|
|
5292
|
-
selector_type: kind
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
6387
|
-
getCommand$
|
|
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$
|
|
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
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
|
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$
|
|
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$
|
|
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,
|
|
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$
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
6781
|
-
const plannedOwner = submittedPlan ? expectString
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
7270
|
-
pikg_digest: expectString
|
|
7544
|
+
handle: expectString(value, "handle"),
|
|
7545
|
+
pikg_digest: expectString(value, "pikg_digest"),
|
|
7271
7546
|
size: expectNumber(value, "size"),
|
|
7272
|
-
purpose: expectString
|
|
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
|
|
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,
|
|
7378
|
-
await ctx.io.stderr(`${JSON.stringify({ action, preflight:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
7542
|
-
expectString
|
|
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$
|
|
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
|
|
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
|
|
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
|
-
|
|
7986
|
-
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
8184
|
-
const OBJECT_OUTPUT$
|
|
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: "
|
|
8189
|
-
commands: [
|
|
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
|
|
8410
|
+
function servicesCommand() {
|
|
8193
8411
|
return {
|
|
8194
|
-
verb: "
|
|
8195
|
-
summary: "
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
-
{
|
|
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")
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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) {
|