aipctl 2026.6.10 → 2026.6.12
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/build/index.cjs +203 -74
- package/docs/api-contract-inventory.md +3 -3
- package/docs/architecture.md +0 -1
- package/package.json +8 -10
package/build/index.cjs
CHANGED
|
@@ -89663,6 +89663,146 @@ const runMain = runMain$1;
|
|
|
89663
89663
|
({
|
|
89664
89664
|
...CommitPrototype$1});
|
|
89665
89665
|
|
|
89666
|
+
const BUILD_ENVS = ["local", "dev", "stage", "prod", "test"];
|
|
89667
|
+
const isBuildEnv = (value) => BUILD_ENVS.includes(value);
|
|
89668
|
+
|
|
89669
|
+
const injectedBuildEnv = "stage".length > 0 ? "stage" : "local";
|
|
89670
|
+
if (!isBuildEnv(injectedBuildEnv)) {
|
|
89671
|
+
throw new Error(`Invalid AIPCTL_BUILD_ENV: ${injectedBuildEnv}`);
|
|
89672
|
+
}
|
|
89673
|
+
const VERSION = "2026.6.12".length > 0 ? "2026.6.12" : "0.0.0";
|
|
89674
|
+
const BUILD_ENV = injectedBuildEnv;
|
|
89675
|
+
const INCLUDE_NATIVE_LOGS = BUILD_ENV !== "prod";
|
|
89676
|
+
|
|
89677
|
+
const loadBinaryModule = () => {
|
|
89678
|
+
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
89679
|
+
return require$1(["..", "binary.cjs"].join("/"));
|
|
89680
|
+
};
|
|
89681
|
+
const resolveNativeBinary = (options = {}) => {
|
|
89682
|
+
const env = options.env ?? process.env;
|
|
89683
|
+
if (env.AIPCTL_NATIVE_BINARY && env.AIPCTL_NATIVE_BINARY.length > 0) {
|
|
89684
|
+
return env.AIPCTL_NATIVE_BINARY;
|
|
89685
|
+
}
|
|
89686
|
+
const binary = (options.loadBinaryModule ?? loadBinaryModule)();
|
|
89687
|
+
return binary.resolveBinaryPath(options.platform ?? process.platform, options.arch ?? process.arch);
|
|
89688
|
+
};
|
|
89689
|
+
const runNativeCommand = (args, options = {}) => new Promise((resolve) => {
|
|
89690
|
+
const env = options.env ?? process.env;
|
|
89691
|
+
const spawn = options.spawn ?? childProcess.spawn;
|
|
89692
|
+
const binaryPath = resolveNativeBinary(options);
|
|
89693
|
+
const child = spawn(binaryPath, [...args], {
|
|
89694
|
+
stdio: "inherit",
|
|
89695
|
+
env
|
|
89696
|
+
});
|
|
89697
|
+
child.on("error", (error) => {
|
|
89698
|
+
console.error(`Failed to start native command: ${error.message}`);
|
|
89699
|
+
process.exitCode = 1;
|
|
89700
|
+
resolve();
|
|
89701
|
+
});
|
|
89702
|
+
child.on("exit", (code) => {
|
|
89703
|
+
process.exitCode = code ?? 1;
|
|
89704
|
+
resolve();
|
|
89705
|
+
});
|
|
89706
|
+
});
|
|
89707
|
+
|
|
89708
|
+
const restArgs = text$2({ name: "arg" }).pipe(
|
|
89709
|
+
repeated,
|
|
89710
|
+
withDescription$5("Arguments passed through to the native aipctl command")
|
|
89711
|
+
);
|
|
89712
|
+
const makeNativeCommand = (name, description) => make$4(
|
|
89713
|
+
name,
|
|
89714
|
+
{ rest: restArgs },
|
|
89715
|
+
({ rest }) => promise$1(() => runNativeCommand([name, ...rest]))
|
|
89716
|
+
).pipe(withDescription(description));
|
|
89717
|
+
|
|
89718
|
+
const nativeCommandDefinitions = [
|
|
89719
|
+
{ name: "install", description: "Install an MCP preset into a local client", includeInProd: true },
|
|
89720
|
+
{ name: "run", description: "Run the native MCP server", includeInProd: true },
|
|
89721
|
+
{ name: "tunnel", description: "Manage Edge Tunnel connections", includeInProd: true },
|
|
89722
|
+
{ name: "logs", description: "Inspect native MCP CLI logs", includeInProd: false }
|
|
89723
|
+
];
|
|
89724
|
+
const nativeCommandNames = nativeCommandDefinitions.map(({ name }) => name);
|
|
89725
|
+
const isEnabledNativeCommand = (definition, includeLogs) => definition.includeInProd || includeLogs;
|
|
89726
|
+
const nativeSubcommands = nativeCommandDefinitions.filter((definition) => isEnabledNativeCommand(definition, INCLUDE_NATIVE_LOGS)).map(({ name, description }) => makeNativeCommand(name, description));
|
|
89727
|
+
const isNativeCommandEnabled = (command, includeLogs = INCLUDE_NATIVE_LOGS) => {
|
|
89728
|
+
const definition = nativeCommandDefinitions.find(({ name }) => name === command);
|
|
89729
|
+
return definition ? isEnabledNativeCommand(definition, includeLogs) : false;
|
|
89730
|
+
};
|
|
89731
|
+
|
|
89732
|
+
const FORCED_ARGS_SEPARATOR = "--";
|
|
89733
|
+
const NATIVE_ROOT_COMMANDS = new Set(nativeCommandNames);
|
|
89734
|
+
const trailingOptionSpecs = [
|
|
89735
|
+
{
|
|
89736
|
+
command: ["drive", "delete"],
|
|
89737
|
+
booleanOptions: /* @__PURE__ */ new Set(["--force", "-f"]),
|
|
89738
|
+
valueOptions: /* @__PURE__ */ new Set(["--org"])
|
|
89739
|
+
},
|
|
89740
|
+
{
|
|
89741
|
+
command: ["automation", "history"],
|
|
89742
|
+
booleanOptions: /* @__PURE__ */ new Set(),
|
|
89743
|
+
valueOptions: /* @__PURE__ */ new Set(["--page", "--org"])
|
|
89744
|
+
},
|
|
89745
|
+
{
|
|
89746
|
+
command: ["automation", "triggers"],
|
|
89747
|
+
booleanOptions: /* @__PURE__ */ new Set(),
|
|
89748
|
+
valueOptions: /* @__PURE__ */ new Set(["--account-id", "--folder-id", "--service-type", "--org"])
|
|
89749
|
+
},
|
|
89750
|
+
{
|
|
89751
|
+
command: ["admin", "skill", "github", "import"],
|
|
89752
|
+
booleanOptions: /* @__PURE__ */ new Set(["--overwrite", "--json"]),
|
|
89753
|
+
valueOptions: /* @__PURE__ */ new Set(["--org", "--pat-env"])
|
|
89754
|
+
}
|
|
89755
|
+
];
|
|
89756
|
+
const getOptionName = (arg) => arg.split("=", 1)[0];
|
|
89757
|
+
const findTrailingOptionSpec = (args) => trailingOptionSpecs.find((spec) => spec.command.every((part, index) => args[index] === part));
|
|
89758
|
+
const isNativeRootCommand = (args) => NATIVE_ROOT_COMMANDS.has(args[0] ?? "");
|
|
89759
|
+
const isBooleanOption = (arg, spec) => spec.booleanOptions.has(arg);
|
|
89760
|
+
const isValueOption = (arg, spec) => spec.valueOptions.has(getOptionName(arg));
|
|
89761
|
+
const normalizeTrailingOptions = (args, spec) => {
|
|
89762
|
+
const options = [];
|
|
89763
|
+
const rest = [];
|
|
89764
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
89765
|
+
const arg = args[index];
|
|
89766
|
+
if (arg === void 0) {
|
|
89767
|
+
continue;
|
|
89768
|
+
}
|
|
89769
|
+
if (isBooleanOption(arg, spec)) {
|
|
89770
|
+
options.push(arg);
|
|
89771
|
+
continue;
|
|
89772
|
+
}
|
|
89773
|
+
if (isValueOption(arg, spec)) {
|
|
89774
|
+
options.push(arg);
|
|
89775
|
+
const nextArg = args[index + 1];
|
|
89776
|
+
if (!arg.includes("=") && nextArg !== void 0 && !nextArg.startsWith("-")) {
|
|
89777
|
+
index += 1;
|
|
89778
|
+
options.push(nextArg);
|
|
89779
|
+
}
|
|
89780
|
+
continue;
|
|
89781
|
+
}
|
|
89782
|
+
rest.push(arg);
|
|
89783
|
+
}
|
|
89784
|
+
return [...options, ...rest];
|
|
89785
|
+
};
|
|
89786
|
+
const normalizeAipArgs = (args) => {
|
|
89787
|
+
if (isNativeRootCommand(args)) {
|
|
89788
|
+
return [...args];
|
|
89789
|
+
}
|
|
89790
|
+
const forcedArgsIndex = args.indexOf(FORCED_ARGS_SEPARATOR);
|
|
89791
|
+
const parsedArgs = forcedArgsIndex === -1 ? args : args.slice(0, forcedArgsIndex);
|
|
89792
|
+
const forcedArgs = forcedArgsIndex === -1 ? [] : args.slice(forcedArgsIndex);
|
|
89793
|
+
const spec = findTrailingOptionSpec(parsedArgs);
|
|
89794
|
+
if (!spec) {
|
|
89795
|
+
return [...args];
|
|
89796
|
+
}
|
|
89797
|
+
const commandPrefix = parsedArgs.slice(0, spec.command.length);
|
|
89798
|
+
const suffix = parsedArgs.slice(spec.command.length);
|
|
89799
|
+
return [
|
|
89800
|
+
...commandPrefix,
|
|
89801
|
+
...normalizeTrailingOptions(suffix, spec),
|
|
89802
|
+
...forcedArgs
|
|
89803
|
+
];
|
|
89804
|
+
};
|
|
89805
|
+
|
|
89666
89806
|
const NOT_LOGGED_IN_MESSAGE = 'Not logged in. Please run "aipctl auth login" first.';
|
|
89667
89807
|
const SESSION_EXPIRED_MESSAGE = 'Session expired. Run "aipctl auth login" to continue.';
|
|
89668
89808
|
|
|
@@ -92674,6 +92814,16 @@ const SENSITIVE_KEY_QUALIFIERS = /* @__PURE__ */ new Set(["api", "access", "priv
|
|
|
92674
92814
|
const SENSITIVE_CONTAINER_KEYS = /* @__PURE__ */ new Set(["auth", "credential", "credentials"]);
|
|
92675
92815
|
const COMMAND_KEY = "command";
|
|
92676
92816
|
const MASKED_COMMAND_KEY = "maskedcommand";
|
|
92817
|
+
const VALUE_KEY = "value";
|
|
92818
|
+
const SENSITIVE_DESCRIPTOR_KEYS = ["key", "name", "label"];
|
|
92819
|
+
const SENSITIVE_DESCRIPTOR_TYPE_SEGMENTS = /* @__PURE__ */ new Set([
|
|
92820
|
+
"password",
|
|
92821
|
+
"secret",
|
|
92822
|
+
"token",
|
|
92823
|
+
"credential",
|
|
92824
|
+
"credentials"
|
|
92825
|
+
]);
|
|
92826
|
+
const DICTIONARY_DESCRIPTOR_TYPE = "dictionary";
|
|
92677
92827
|
const SENSITIVE_QUERY_KEYS = /* @__PURE__ */ new Set([
|
|
92678
92828
|
"token",
|
|
92679
92829
|
"accesstoken",
|
|
@@ -92732,6 +92882,40 @@ function isFullyRedactedKey(key) {
|
|
|
92732
92882
|
function isSensitiveContainerKey(key) {
|
|
92733
92883
|
return SENSITIVE_CONTAINER_KEYS.has(normalizeKey(key));
|
|
92734
92884
|
}
|
|
92885
|
+
function getStringRecordValue(record, key) {
|
|
92886
|
+
const value = record[key];
|
|
92887
|
+
return typeof value === "string" ? value : void 0;
|
|
92888
|
+
}
|
|
92889
|
+
function hasSensitiveTypeDescriptor(record) {
|
|
92890
|
+
const type = getStringRecordValue(record, "type");
|
|
92891
|
+
if (!type) {
|
|
92892
|
+
return false;
|
|
92893
|
+
}
|
|
92894
|
+
const normalized = normalizeKey(type);
|
|
92895
|
+
if (SENSITIVE_DESCRIPTOR_TYPE_SEGMENTS.has(normalized)) {
|
|
92896
|
+
return true;
|
|
92897
|
+
}
|
|
92898
|
+
return getKeySegments(type).some((segment) => SENSITIVE_DESCRIPTOR_TYPE_SEGMENTS.has(segment));
|
|
92899
|
+
}
|
|
92900
|
+
function hasSensitiveNameDescriptor(record) {
|
|
92901
|
+
return SENSITIVE_DESCRIPTOR_KEYS.some((key) => {
|
|
92902
|
+
const descriptor = getStringRecordValue(record, key);
|
|
92903
|
+
return descriptor ? isFullyRedactedKey(descriptor) : false;
|
|
92904
|
+
});
|
|
92905
|
+
}
|
|
92906
|
+
function isSensitiveDescriptor(record) {
|
|
92907
|
+
return hasSensitiveTypeDescriptor(record) || hasSensitiveNameDescriptor(record);
|
|
92908
|
+
}
|
|
92909
|
+
function isDictionaryDescriptor(record) {
|
|
92910
|
+
return normalizeKey(getStringRecordValue(record, "type") ?? "") === DICTIONARY_DESCRIPTOR_TYPE;
|
|
92911
|
+
}
|
|
92912
|
+
function maskDictionaryString(value, options) {
|
|
92913
|
+
try {
|
|
92914
|
+
return JSON.stringify(maskSensitiveData(JSON.parse(value), options));
|
|
92915
|
+
} catch {
|
|
92916
|
+
return maskSensitiveText(value);
|
|
92917
|
+
}
|
|
92918
|
+
}
|
|
92735
92919
|
function isSensitiveQueryKey(key, preserveOAuthAuthorizeParams) {
|
|
92736
92920
|
const normalized = normalizeKey(key);
|
|
92737
92921
|
if (preserveOAuthAuthorizeParams && OAUTH_PRESERVED_QUERY_KEYS.has(normalized)) {
|
|
@@ -92837,6 +93021,14 @@ function maskSensitiveData(value, options = {}, context = {}) {
|
|
|
92837
93021
|
masked[key] = record.maskedCommand;
|
|
92838
93022
|
continue;
|
|
92839
93023
|
}
|
|
93024
|
+
if (normalizedKey === VALUE_KEY && isSensitiveDescriptor(record)) {
|
|
93025
|
+
masked[key] = entry == null ? entry : REDACTED_VALUE;
|
|
93026
|
+
continue;
|
|
93027
|
+
}
|
|
93028
|
+
if (normalizedKey === VALUE_KEY && typeof entry === "string" && isDictionaryDescriptor(record)) {
|
|
93029
|
+
masked[key] = maskDictionaryString(entry, options);
|
|
93030
|
+
continue;
|
|
93031
|
+
}
|
|
92840
93032
|
if (isFullyRedactedKey(key)) {
|
|
92841
93033
|
if (entry !== null && typeof entry === "object") {
|
|
92842
93034
|
masked[key] = maskSensitiveData(entry, options, {
|
|
@@ -93610,7 +93802,7 @@ const makeRequest = (baseUrl, path, accessToken, options) => tryPromise({
|
|
|
93610
93802
|
if (!response.ok) {
|
|
93611
93803
|
throw await toApiError(response);
|
|
93612
93804
|
}
|
|
93613
|
-
if (response.status === 202 || response.status === 204) {
|
|
93805
|
+
if (options?.skipJsonParse || response.status === 202 || response.status === 204) {
|
|
93614
93806
|
return void 0;
|
|
93615
93807
|
}
|
|
93616
93808
|
return await response.json();
|
|
@@ -94334,11 +94526,9 @@ const ApiServiceLive = effect$1(
|
|
|
94334
94526
|
yield* requireChatBaseUrlEffect();
|
|
94335
94527
|
const token = yield* getAccessToken();
|
|
94336
94528
|
const params = new URLSearchParams();
|
|
94337
|
-
params.set("pageSize", String(options?.pageSize ?? 25));
|
|
94338
|
-
params.set("sortBy", "updatedAt");
|
|
94339
|
-
params.set("sortDirection", "desc");
|
|
94340
94529
|
if (options?.cursor) params.set("cursor", options.cursor);
|
|
94341
|
-
const
|
|
94530
|
+
const query = params.toString();
|
|
94531
|
+
const path = `/librechat/api/${encodeURIComponent(orgSlug)}/convos${query ? `?${query}` : ""}`;
|
|
94342
94532
|
return yield* makeRequest(chatBaseUrl, path, token);
|
|
94343
94533
|
}),
|
|
94344
94534
|
getConversation: (orgSlug, conversationId) => gen(function* () {
|
|
@@ -94378,7 +94568,7 @@ const ApiServiceLive = effect$1(
|
|
|
94378
94568
|
exportInstalledAgent: (orgSlug, agentId) => gen(function* () {
|
|
94379
94569
|
const resolvedApiBaseUrl = yield* requireApiBaseUrlEffect();
|
|
94380
94570
|
const token = yield* getAccessToken();
|
|
94381
|
-
const path = `/
|
|
94571
|
+
const path = `/web/admin/organizations/slug/${encodeURIComponent(orgSlug)}/installed-agents/${encodeURIComponent(agentId)}/export`;
|
|
94382
94572
|
return yield* tryPromise({
|
|
94383
94573
|
try: async () => {
|
|
94384
94574
|
const response = await rateLimitedFetch(`${resolvedApiBaseUrl}${path}`, {
|
|
@@ -94557,7 +94747,7 @@ const ApiServiceLive = effect$1(
|
|
|
94557
94747
|
deletePreset: (presetId) => gen(function* () {
|
|
94558
94748
|
const token = yield* getAccessToken();
|
|
94559
94749
|
const path = `/api/web/presets/${encodeURIComponent(presetId)}`;
|
|
94560
|
-
return yield* makeRequest(baseUrl, path, token, { method: "DELETE" });
|
|
94750
|
+
return yield* makeRequest(baseUrl, path, token, { method: "DELETE", skipJsonParse: true });
|
|
94561
94751
|
}),
|
|
94562
94752
|
setPresetAsDefault: (presetId) => gen(function* () {
|
|
94563
94753
|
const token = yield* getAccessToken();
|
|
@@ -99707,72 +99897,6 @@ const skillCommand = make$4("skill", {}).pipe(
|
|
|
99707
99897
|
withSubcommands(skillSubcommands)
|
|
99708
99898
|
);
|
|
99709
99899
|
|
|
99710
|
-
const BUILD_ENVS = ["local", "dev", "qa", "stage", "prod", "test"];
|
|
99711
|
-
const isBuildEnv = (value) => BUILD_ENVS.includes(value);
|
|
99712
|
-
|
|
99713
|
-
const injectedBuildEnv = "dev".length > 0 ? "dev" : "local";
|
|
99714
|
-
if (!isBuildEnv(injectedBuildEnv)) {
|
|
99715
|
-
throw new Error(`Invalid AIPCTL_BUILD_ENV: ${injectedBuildEnv}`);
|
|
99716
|
-
}
|
|
99717
|
-
const VERSION = "2026.6.10".length > 0 ? "2026.6.10" : "0.0.0";
|
|
99718
|
-
const BUILD_ENV = injectedBuildEnv;
|
|
99719
|
-
const INCLUDE_NATIVE_LOGS = BUILD_ENV !== "prod";
|
|
99720
|
-
|
|
99721
|
-
const loadBinaryModule = () => {
|
|
99722
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
99723
|
-
return require$1(["..", "binary.cjs"].join("/"));
|
|
99724
|
-
};
|
|
99725
|
-
const resolveNativeBinary = (options = {}) => {
|
|
99726
|
-
const env = options.env ?? process.env;
|
|
99727
|
-
if (env.AIPCTL_NATIVE_BINARY && env.AIPCTL_NATIVE_BINARY.length > 0) {
|
|
99728
|
-
return env.AIPCTL_NATIVE_BINARY;
|
|
99729
|
-
}
|
|
99730
|
-
const binary = (options.loadBinaryModule ?? loadBinaryModule)();
|
|
99731
|
-
return binary.resolveBinaryPath(options.platform ?? process.platform, options.arch ?? process.arch);
|
|
99732
|
-
};
|
|
99733
|
-
const runNativeCommand = (args, options = {}) => new Promise((resolve) => {
|
|
99734
|
-
const env = options.env ?? process.env;
|
|
99735
|
-
const spawn = options.spawn ?? childProcess.spawn;
|
|
99736
|
-
const binaryPath = resolveNativeBinary(options);
|
|
99737
|
-
const child = spawn(binaryPath, [...args], {
|
|
99738
|
-
stdio: "inherit",
|
|
99739
|
-
env
|
|
99740
|
-
});
|
|
99741
|
-
child.on("error", (error) => {
|
|
99742
|
-
console.error(`Failed to start native command: ${error.message}`);
|
|
99743
|
-
process.exitCode = 1;
|
|
99744
|
-
resolve();
|
|
99745
|
-
});
|
|
99746
|
-
child.on("exit", (code) => {
|
|
99747
|
-
process.exitCode = code ?? 1;
|
|
99748
|
-
resolve();
|
|
99749
|
-
});
|
|
99750
|
-
});
|
|
99751
|
-
|
|
99752
|
-
const restArgs = text$2({ name: "arg" }).pipe(
|
|
99753
|
-
repeated,
|
|
99754
|
-
withDescription$5("Arguments passed through to the native aipctl command")
|
|
99755
|
-
);
|
|
99756
|
-
const makeNativeCommand = (name, description) => make$4(
|
|
99757
|
-
name,
|
|
99758
|
-
{ rest: restArgs },
|
|
99759
|
-
({ rest }) => promise$1(() => runNativeCommand([name, ...rest]))
|
|
99760
|
-
).pipe(withDescription(description));
|
|
99761
|
-
|
|
99762
|
-
const nativeCommandDefinitions = [
|
|
99763
|
-
{ name: "install", description: "Install an MCP preset into a local client", includeInProd: true },
|
|
99764
|
-
{ name: "run", description: "Run the native MCP server", includeInProd: true },
|
|
99765
|
-
{ name: "tunnel", description: "Manage Edge Tunnel connections", includeInProd: true },
|
|
99766
|
-
{ name: "logs", description: "Inspect native MCP CLI logs", includeInProd: false }
|
|
99767
|
-
];
|
|
99768
|
-
nativeCommandDefinitions.map(({ name }) => name);
|
|
99769
|
-
const isEnabledNativeCommand = (definition, includeLogs) => definition.includeInProd || includeLogs;
|
|
99770
|
-
const nativeSubcommands = nativeCommandDefinitions.filter((definition) => isEnabledNativeCommand(definition, INCLUDE_NATIVE_LOGS)).map(({ name, description }) => makeNativeCommand(name, description));
|
|
99771
|
-
const isNativeCommandEnabled = (command, includeLogs = INCLUDE_NATIVE_LOGS) => {
|
|
99772
|
-
const definition = nativeCommandDefinitions.find(({ name }) => name === command);
|
|
99773
|
-
return definition ? isEnabledNativeCommand(definition, includeLogs) : false;
|
|
99774
|
-
};
|
|
99775
|
-
|
|
99776
99900
|
const mainCommandDescription = "AIP command-line interface for managing organizations, skills, and native MCP commands";
|
|
99777
99901
|
const rootSubcommands = [
|
|
99778
99902
|
adminCommand,
|
|
@@ -99917,7 +100041,12 @@ const cli = run(mainCommand, {
|
|
|
99917
100041
|
const BaseLayer = mergeAll$1(ConfigServiceLive, CredentialServiceLive);
|
|
99918
100042
|
const ApiLayer = provide(ApiServiceLive, BaseLayer);
|
|
99919
100043
|
const AppLayer = merge$2(BaseLayer, ApiLayer);
|
|
99920
|
-
|
|
100044
|
+
const argv = [
|
|
100045
|
+
process.argv[0] ?? "node",
|
|
100046
|
+
process.argv[1] ?? "aipctl",
|
|
100047
|
+
...normalizeAipArgs(args)
|
|
100048
|
+
];
|
|
100049
|
+
cli(argv).pipe(
|
|
99921
100050
|
provide$1(AppLayer),
|
|
99922
100051
|
provide$1(layer),
|
|
99923
100052
|
runMain
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
| SKILL-05 | skill-admin | `aipctl skill download`; `aipctl admin skill upload`, `aipctl admin skill download`, `aipctl admin skill github inspect/import/sync/credentials set/clear` | `createAdminUploadUrl` → `uploadToS3` → `completeAdminUpload` (`abortAdminUpload` on failure); `getSkillDownloadUrl` → `downloadFromUrl`; `inspectGitHubSkillSource`, `prepareGitHubSkill`, `syncPrepareGitHubSkill`, `updateGitHubSkillCredentials` | api + external | `POST`/`PUT`/`POST`; `POST`/`GET`; `POST`, `POST`, `POST`, `PATCH` | `/admin/.../skills/upload-url`; `/admin/.../skills/download-url`; `/admin/.../skills/github-repo-inspect`; `/github-prepare`; `/{skillId}/sync-prepare`; `/{skillId}/github-credentials` | upload/download local bodies; GitHub inspect/prepare `{ url, pat? }`; credentials `{ pat or null }` | upload/download/GitHub admin skill DTOs | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/upload-url"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/download-url"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/github-repo-inspect"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/github-prepare"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/{skillId}/sync-prepare"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/{skillId}/github-credentials"]` | `external-presigned` | N/A | `keep` | none | N/A | existing `commands/admin/skill.test.ts`, `commands/skill/skill-extended.test.ts`; needed GitHub admin skill contract fixtures |
|
|
51
51
|
| P1-SKILL-01 | skill-docs | `aipctl skill get --json`, `aipctl admin skill get --json`, `aipctl admin skill github import/sync --json` | same owners as `SKILL-01`/`SKILL-05` | api | same as upstream rows | same as upstream rows | runtime/JSON/help/docs now align on `source`, `origin`, `updateAvailable`, `secretsAvailable`, GitHub metadata, `secretKeys`; stale `version` and file `size` removed | JSON/help/docs contract for skill objects | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#components[...]` | `generated-ready` | `P1` | `keep` | none | N/A | updated `src/core/api.test.ts`, `commands/skill/skill.test.ts`, `commands/skill/skill-extended.test.ts`, `commands/admin/skill.test.ts`, `commands/json-format.test.ts`, `../docs/how-to/aip-cli-usage.md`; covers JSON/help/docs field sync |
|
|
52
52
|
| P0-AGENT-01 | agent-user | `aipctl agent list`, `aipctl agent get` | `listInstalledAgents`, `getInstalledAgent` | api | `GET`, `GET` | `/api/web/organizations/slug/{organizationSlug}/installed-agents`; `/installed-agents/{installedAgentId}` | legacy implemented endpoint maps `list`/`installedAgentId` into CLI `data`/`id`; detail wraps legacy response in `{ data }` and maps `installedIntegrationList` fallback | local `ListInstalledAgentsResponse`, `{ data: InstalledAgentDetail }` | implemented: `resource/oas/duplo.yaml`; future v2 source: `resource/oas/modules/backend/agent/user/openapi.yaml` | legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/installed-agents"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/installed-agents/{installedAgentId}"]` | `legacy-generated` | `P0` | `keep legacy` | owner=`backend app AgentsApiController`; rationale=`agent v2 controllers currently throw NotImplementedError in this repo, so public beta must call implemented legacy endpoints`; removal condition=`AgentUserApiController v2 methods are implemented and deployed`; incorporation plan=`switch to agent v2 OAS/generated contract only after backend implementation lands` | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/agent/agent.test.ts`; covers implemented legacy list/detail path and response mapping |
|
|
53
|
-
| P0-AGENT-02 | agent-admin | `aipctl admin agent create`, `update`, `delete`, `export`, `share`, `templates`; `aipctl agent enable`, `disable` | `createInstalledAgent`, `updateInstalledAgent`, `deleteInstalledAgent`, `exportInstalledAgent`, `getInstalledAgentShare`, `listAgentTemplates`, `updateInstalledAgentStatus` | api | `POST`, `PATCH`, `DELETE`, `GET`, `GET`, `GET`, `PATCH` | `/api/web/admin/organizations/slug/{organizationSlug}/installed-agents`; `/{installedAgentId}`; `/export`; `/share`; `/agents`; `/{installedAgentId}/status` | create/update bodies follow implemented legacy admin request (`custom.iconKeyOrUrl`, `knowledgeBundleIdList`); templates map legacy `agentId`/`label`/`categoryList`; status body `{ status }` | create/update return plain `{ id }`; local admin agent DTOs + `Buffer` export | implemented: `resource/oas/duplo.yaml`; future v2 source: `resource/oas/modules/backend/agent/admin/openapi.yaml` | legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/admin/organizations/slug/{organizationSlug}/installed-agents"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/installed-agents/{installedAgentId}"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/agents"]
|
|
53
|
+
| P0-AGENT-02 | agent-admin | `aipctl admin agent create`, `update`, `delete`, `export`, `share`, `templates`; `aipctl agent enable`, `disable` | `createInstalledAgent`, `updateInstalledAgent`, `deleteInstalledAgent`, `exportInstalledAgent`, `getInstalledAgentShare`, `listAgentTemplates`, `updateInstalledAgentStatus` | api | `POST`, `PATCH`, `DELETE`, `GET`, `GET`, `GET`, `PATCH` | `/api/web/admin/organizations/slug/{organizationSlug}/installed-agents`; `/{installedAgentId}`; export uses legacy direct `/web/admin/organizations/slug/{organizationSlug}/installed-agents/{installedAgentId}/export`; `/share`; `/agents`; `/{installedAgentId}/status` | create/update bodies follow implemented legacy admin request (`custom.iconKeyOrUrl`, `knowledgeBundleIdList`); export is YAML bytes from direct controller path; templates map legacy `agentId`/`label`/`categoryList`; status body `{ status }` | create/update return plain `{ id }`; local admin agent DTOs + `Buffer` export | implemented: `resource/oas/duplo.yaml`; export controller path: `backend/api/src/main/kotlin/com/querypie/duplo/api/app/controller/AgentExportController.kt`; future v2 source: `resource/oas/modules/backend/agent/admin/openapi.yaml` | legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/admin/organizations/slug/{organizationSlug}/installed-agents"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/installed-agents/{installedAgentId}"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/agents"]`; export path intentionally OAS-codegen excluded | `legacy-generated` | `P0` | `keep legacy` | owner=`backend app AgentsApiController + AgentExportController`; rationale=`agent v2 admin controllers currently throw NotImplementedError and export is implemented only at /web/admin direct controller path in PROD`; removal condition=`AgentAdminApiController v2 and export path are implemented/deployed under versioned OAS path`; incorporation plan=`switch to agent v2 OAS/generated contract only after backend implementation lands, then remove direct export exception` | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/agent/agent.test.ts`; covers implemented legacy CRUD/status/template path/body, direct export path, Buffer response, and 404 propagation |
|
|
54
54
|
| P1-CHAT-01 | agent-chat | `aipctl agent chat` | `agentNewChat`, `agentChat`, local `parseSseStream` | chat | `POST` + SSE | `/librechat/api/{orgSlug}/agent/new-chat`; `/librechat/api/{orgSlug}/agent/chat` | request body `{ agentInstallationId or conversationId, text, files: [] }` | local `AgentChatResult { text, conversationId }` parsed from SSE event fields `final`, `conversation.conversationId`, `responseMessage` | path source: `resource/oas/chat.yaml` | `frontend/packages/api/src/out/chat-types.ts#paths["/librechat/api/{orgSlug}/agent/new-chat"]`, `#paths["/librechat/api/{orgSlug}/agent/chat"]` | `stream-exception` | `P1` | `legacy-exception` | owner=`chat backend agent SSE stream contract`; rationale=`path exists in OpenAPI but final SSE event payload is still out-of-band`; removal condition=`official SSE event schema or versioned fixture is published with the chat contract`; incorporation plan=`bind CLI parser/tests to the published SSE fixture and drop local-only stream assumptions` | N/A | updated `src/core/api.test.ts`; covers content[] text, fallback text, malformed event skip, and no-final-event failure |
|
|
55
55
|
| P1-AUTO-01 | automation | `aipctl automation list`, `get`, `create`, `update`, `delete`, `run`, `enable`, `disable`, `history`, `cancel`, `webhook-regen`, `triggers` | `listAutomations`, `getAutomation`, `createAutomation`, `updateAutomation`, `deleteAutomation`, `runAutomation`, `updateAutomationStatus`, `listAutomationHistories`, `cancelAutomationHistory`, `regenerateWebhookUrl`, `getTriggerProviderMetadata` | api | `GET`, `POST`, `PUT`, `DELETE` mix | `/api/web/organizations/slug/{organizationSlug}/automations...`; `/automation-trigger-providers/.../metadata` | automation pagination normalized to `{ page, pageSize, total }`; metadata calls now use provider-specific OAS paths and required args (`accountId`, `folderId`, `serviceType`) | local automation DTOs + webhook URL DTO | `resource/oas/modules/backend/automation/user/openapi.yaml` | `frontend/packages/api/src/out/modules/automation-user-types.ts#paths[...]` | `generated-ready` | `P1` | `keep` | none | N/A | updated `src/core/api.test.ts`, `commands/automation/automation.test.ts`, `commands/json-format.test.ts`; covers official pagination fields, provider-specific metadata routes, and unsupported-provider preflight failure |
|
|
56
|
-
| CHAT-01 | chat-readonly | `aipctl chat list`, `aipctl chat get`, `aipctl chat messages` | `listConversations`, `getConversation`, `listMessages` | chat | `GET` | `/librechat/api/{orgSlug}/convos`; `/convos/{conversationId}`; `/messages/{conversationId}` | list query
|
|
56
|
+
| CHAT-01 | chat-readonly | `aipctl chat list`, `aipctl chat get`, `aipctl chat messages` | `listConversations`, `getConversation`, `listMessages` | chat | `GET` | `/librechat/api/{orgSlug}/convos`; `/convos/{conversationId}`; `/messages/{conversationId}` | list sends no default query; optional cursor only (`?cursor=...`). `pageSize`/`sortBy`/`sortDirection` defaults removed due deployed Chat validation drift | local `ListConversationsResponse`, `ConversationDetail`, `ChatMessage[]` | `resource/oas/chat.yaml` | `frontend/packages/api/src/out/chat-types.ts#paths["/librechat/api/{orgSlug}/convos"]`, `#paths["/librechat/api/{orgSlug}/convos/{conversationId}"]`, `#paths["/librechat/api/{orgSlug}/messages/{conversationId}"]` | `legacy-generated` | N/A | `keep` | owner=`chat backend`; rationale=`PROD rejects CLI default pageSize/sort query while no-query and cursor-only read path are safe`; removal condition=`chat deployed contract publishes and accepts explicit pagination query for public CLI`; incorporation plan=`reintroduce explicit pagination only after OAS/source/deployed validation align` | N/A | updated `src/core/api.test.ts`, existing `commands/chat/chat.test.ts`; covers default no-query and cursor-only URL |
|
|
57
57
|
| P0-DRIVE-01 | drive | `aipctl drive list`, `download`, `delete`, `mkdir`, `rename`, `usage` | `listDriveEntries`, `getDriveDownloadUrl`, `deleteDriveEntries`, `createDriveFolder`, `renameDriveEntry`, `getDriveUsage`, `downloadFromUrl` | api + external | `GET`, `POST`, `POST`, `POST`, `PATCH`, `GET`, external `GET` | `/drive/entries?count=200`; `/drive/entries/download-url`; `/drive/entries/delete`; `/drive/entries/{entryId}`; `/drive/usage` | official list `{ path, hasNext, nextCursor, items }`; delete body `{ entryIds[] }`; rename body `{ newName }`; download body `{ entryIds: [id] }` | official drive list/download DTOs + external file buffer | `resource/oas/modules/backend/organization/storage/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-storage-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/download-url"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/{entryId}"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/delete"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/usage"]` | `generated-ready` | `P0` | `migrate` | none | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/drive/drive.test.ts`; covers paged list shape, batch download-url request, DTO field rename (`sizeBytes`, `modifiedAt`) |
|
|
58
58
|
| P0-DRIVE-02 | drive | `aipctl drive upload` | `createDriveUploadUrl` → `uploadToS3` → `completeDriveUpload` | api + external | `POST` → `PUT` → `POST` | `/drive/entries/upload-url`; external presigned `uploadUrl`; `/drive/entries/{entryId}/complete` | official upload request `{ parentId: null, filename, fileSize, mimeType }` | official `CreateDriveUploadUrlResponse { id, filename, uploadUrl, headers }` then `void` | `resource/oas/modules/backend/organization/storage/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-storage-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/upload-url"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/{entryId}/complete"]` | `generated-ready` | `P0` | `migrate` | none | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/drive/drive.test.ts`; covers `parentId: null` request and response `id`/`filename` usage |
|
|
59
59
|
| P1-INT-01 | integration | `aipctl integration list`, `test`; `aipctl admin integration get`, `update`, `delete`, `tools`, `available` | `listIntegrations`, `testIntegration`, `getIntegration`, `updateIntegration`, `deleteIntegration`, `listIntegrationTools`, `listConfigurableIntegrations` | api | `GET`, `POST`, `GET`, `PUT`, `DELETE`, `GET`, `GET` | `/api/web/integrations/v2`; `/api/web/integration/{integrationId}/test`; `/api/web/admin/organizations/slug/{organizationSlug}/integrations/{integrationId}`; `/{integrationId}/tools`; `/configurable-integrations` | top-level list/test and admin detail/available now follow current/legacy OAS path+body+DTO where available; admin update/delete still accept untyped legacy mutation body/path until admin mutation contract lands | local `Integration`, `IntegrationDetail`, `IntegrationToolsResponse`, `ConfigurableIntegration[]` | legacy admin paths: `resource/oas/duplo-web.yaml`; partial modern source: `resource/oas/modules/backend/integration/openapi.yaml` (does not cover these admin list/CRUD/tools paths) | legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/admin/organizations/slug/{organizationSlug}/integrations"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/configurable-integrations"]`; partial current `frontend/packages/api/src/out/modules/integration-types.ts` lacks these admin list/CRUD/tools paths | `legacy-generated` | `P1` | `legacy-exception` | owner=`backend app Integrations / duplo-web legacy OAS`; rationale=`public beta keeps integration list/test/admin detail/tools/available, but admin update/delete still lack an approved current contract outside legacy duplo-web`; removal condition=`independent contract covers user list/test plus admin CRUD/tools/available`; incorporation plan=`extend integration module or independent contract for list/test/admin CRUD/tools/available, then retire legacy path/body mappings and delete/update exception` | N/A | updated `src/core/api.test.ts`, `commands/integration/integration.test.ts`; covers v2 list query, test body `{ organizationSlug }`, admin detail/tools DTO fields, configurable wrapper unwrap, and pinned update/delete legacy paths |
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
| USAGE-01 | usage | `aipctl admin usage credit`, `top-users`, `daily-graph`, `daily-users`, `mcp-top` | `getCreditStatistics`, `getCreditTopUsers`, `getCreditDailyGraph`, `getCreditDailyUsers`, `getMcpTopTools` | api | `GET` | `/api/web/admin/organizations/slug/{organizationSlug}/usage/...` | query `{ startDt,endDt,limit,pageNumber,pageSize,userId }` | local usage DTOs, `DailyUsageDetailsResponse.pagination { page,pageSize,total }` | `resource/oas/modules/backend/usage/openapi.yaml` | `frontend/packages/api/src/out/modules/usage-types.ts#paths[...]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/usage/usage.test.ts`; needed generated path snapshots |
|
|
62
62
|
| AUDIT-01 | audit | `aipctl admin audit list`, `types` | `listAuditLogs`, `listAuditEventTypes` | api | `GET` | `/api/web/audit/organization/slug/{organizationSlug}`; `/api/web/audit/event/types` | query `{ eventType,page,pageSize }` | local `ListAuditResponse`, `AuditEventType[]` | `resource/oas/modules/backend/audit/openapi.yaml` | `frontend/packages/api/src/out/modules/backend-audit-types.ts#paths[...]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/audit/audit.test.ts`; needed generated path snapshots |
|
|
63
63
|
| TUNNEL-01 | tunnel | `aipctl admin tunnel status`, `config`, `token` | `getTunnelStatus`, `getTunnelConfig`, `createTunnelToken` | api | `GET`, `GET`, `POST` | `/api/web/edge-tunnel/v2/organizations/slug/{organizationSlug}/status`; `/config`; `/token` | none | local `TunnelStatus`, `TunnelConfig`, `void` | `resource/oas/modules/backend/tunnel/openapi.yaml` | `frontend/packages/api/src/out/modules/tunnel-types.ts#paths[...]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/tunnel/tunnel.test.ts`; needed v2 path snapshot |
|
|
64
|
-
| P1-PRESET-01 | preset | `aipctl admin preset list`, `get`, `create`, `update`, `rename`, `delete`, `set-default`, `unset-default`, `regen-key`, `regen-static-key` | `listPresets`, `getPreset`, `createPreset`, `updatePreset`, `renamePreset`, `deletePreset`, `setPresetAsDefault`, `unsetPresetAsDefault`, `regenPresetKey`, `regenPresetStaticKey` | api | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` mix | `/api/web/presets/v2`; `/api/web/presets/{presetId}`; `/key`; `/static-key`; `/default` | legacy preset API kept
|
|
64
|
+
| P1-PRESET-01 | preset | `aipctl admin preset list`, `get`, `create`, `update`, `rename`, `delete`, `set-default`, `unset-default`, `regen-key`, `regen-static-key` | `listPresets`, `getPreset`, `createPreset`, `updatePreset`, `renamePreset`, `deletePreset`, `setPresetAsDefault`, `unsetPresetAsDefault`, `regenPresetKey`, `regenPresetStaticKey` | api | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` mix | `/api/web/presets/v2`; `/api/web/presets/{presetId}`; `/key`; `/static-key`; `/default` | legacy preset API kept; delete response is contract-aligned to 204 No Content and CLI treats delete as endpoint-specific void response to tolerate deployed 200 empty drift | local preset DTOs with installation/json command fields; delete returns `void` | `resource/oas/duplo-web.yaml` | `frontend/packages/api/src/out/user-types.ts#paths["/api/web/presets/v2"]`, `#paths["/api/web/presets/{presetId}"]`, `#paths["/api/web/presets/{presetId}/default"]` | `legacy-generated` | `P1` | `keep` | owner=`backend app PresetsApiController`; rationale=`runtime returned 200 empty while generated/OAS says 204, causing JSON parse false failure`; removal condition=`204 is deployed everywhere and CLI no longer needs 200-empty tolerance`; incorporation plan=`keep endpoint-specific void mode, do not add global 200-empty fallback` | N/A | updated `src/core/api.test.ts`, `commands/admin/preset/preset.test.ts`, `../docs/how-to/aip-cli-usage.md`, `backend/api/src/test/kotlin/.../PresetsApiControllerTest.kt`; covers admin namespace docs, `/v2`, `/{id}`, `/default`, `/key`, `/static-key`, delete 200-empty tolerance, and JSON endpoint 200-empty failure |
|
|
65
65
|
|
|
66
66
|
## Queue IDs for follow-up
|
|
67
67
|
|
package/docs/architecture.md
CHANGED
|
@@ -60,7 +60,6 @@ desktop/packages/cli/
|
|
|
60
60
|
- package base version: `0.0.0`
|
|
61
61
|
- publish-time CalVer가 `AIPCTL_VERSION`으로 TS bundle과 Go ldflags에 주입됩니다.
|
|
62
62
|
- `AIPCTL_BUILD_ENV`는 `local|dev|stage|prod|test` 중 하나이며 `logs` gating에 사용됩니다.
|
|
63
|
-
- native input hash가 이전 발행본과 같으면 platform package를 새로 빌드하지 않고 기존 version을 재사용합니다.
|
|
64
63
|
|
|
65
64
|
## Dependency direction
|
|
66
65
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aipctl",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.12",
|
|
4
4
|
"description": "QueryPie AIP and MCP CLI tool",
|
|
5
5
|
"author": "QueryPie",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -22,16 +22,14 @@
|
|
|
22
22
|
"node": ">=24.18.0"
|
|
23
23
|
},
|
|
24
24
|
"metadata": {
|
|
25
|
-
"contentHash": "
|
|
26
|
-
"wrapperHash": "f48be2ddee664246e0bfd64966a9a4af566c63674ec7fc998a5c0e8bbe4a2fdb",
|
|
27
|
-
"nativeHash": "c162f6578140a53a3870e776304ae7e1331480ba7da919088a25ac39108af5b9"
|
|
25
|
+
"contentHash": "2e0b362640a656e8332cc6cb84843436a981b7d13547893c1fd8ca14382d0fc0"
|
|
28
26
|
},
|
|
29
27
|
"optionalDependencies": {
|
|
30
|
-
"aipctl-darwin-x64": "2026.6.
|
|
31
|
-
"aipctl-darwin-arm64": "2026.6.
|
|
32
|
-
"aipctl-linux-x64": "2026.6.
|
|
33
|
-
"aipctl-linux-arm64": "2026.6.
|
|
34
|
-
"aipctl-windows-x64": "2026.6.
|
|
35
|
-
"aipctl-windows-arm64": "2026.6.
|
|
28
|
+
"aipctl-darwin-x64": "2026.6.12",
|
|
29
|
+
"aipctl-darwin-arm64": "2026.6.12",
|
|
30
|
+
"aipctl-linux-x64": "2026.6.12",
|
|
31
|
+
"aipctl-linux-arm64": "2026.6.12",
|
|
32
|
+
"aipctl-windows-x64": "2026.6.12",
|
|
33
|
+
"aipctl-windows-arm64": "2026.6.12"
|
|
36
34
|
}
|
|
37
35
|
}
|