aipctl 2026.9.7 → 2026.9.9
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 +107 -112
- package/docs/api-contract-inventory.md +11 -7
- package/package.json +3 -3
package/build/index.cjs
CHANGED
|
@@ -778,7 +778,7 @@ const isIterable = input => typeof input === "string" || hasProperty(input, Symb
|
|
|
778
778
|
* @since 2.0.0
|
|
779
779
|
* @see isObject
|
|
780
780
|
*/
|
|
781
|
-
const isRecord$
|
|
781
|
+
const isRecord$2 = input => isRecordOrArray(input) && !Array.isArray(input);
|
|
782
782
|
/**
|
|
783
783
|
* A refinement that checks if a value is `PromiseLike`. It performs a duck-typing
|
|
784
784
|
* check for a `.then` method.
|
|
@@ -25158,7 +25158,7 @@ const go = (ast, isDecoding) => {
|
|
|
25158
25158
|
const concurrency = getConcurrency(ast);
|
|
25159
25159
|
const batching = getBatching(ast);
|
|
25160
25160
|
return (input, options) => {
|
|
25161
|
-
if (!isRecord$
|
|
25161
|
+
if (!isRecord$2(input)) {
|
|
25162
25162
|
return left(new Type(ast, input));
|
|
25163
25163
|
}
|
|
25164
25164
|
const allErrors = options?.errors === "all";
|
|
@@ -89670,7 +89670,7 @@ const injectedBuildEnv = "dev".length > 0 ? "dev" : "local";
|
|
|
89670
89670
|
if (!isBuildEnv(injectedBuildEnv)) {
|
|
89671
89671
|
throw new Error(`Invalid AIPCTL_BUILD_ENV: ${injectedBuildEnv}`);
|
|
89672
89672
|
}
|
|
89673
|
-
const VERSION = "2026.9.
|
|
89673
|
+
const VERSION = "2026.9.9".length > 0 ? "2026.9.9" : "0.0.0";
|
|
89674
89674
|
const BUILD_ENV = injectedBuildEnv;
|
|
89675
89675
|
const INCLUDE_NATIVE_LOGS = BUILD_ENV !== "prod";
|
|
89676
89676
|
|
|
@@ -89804,6 +89804,14 @@ const normalizeAipArgs = (args) => {
|
|
|
89804
89804
|
};
|
|
89805
89805
|
|
|
89806
89806
|
const implementedCommandOperationIds = /* @__PURE__ */ new Set([
|
|
89807
|
+
"listCliAgents",
|
|
89808
|
+
"getCliAgent",
|
|
89809
|
+
"listCliAgentTemplates",
|
|
89810
|
+
"createCliAgent",
|
|
89811
|
+
"updateCliAgent",
|
|
89812
|
+
"deleteCliAgent",
|
|
89813
|
+
"updateCliAgentStatus",
|
|
89814
|
+
"getCliAgentShare",
|
|
89807
89815
|
"getCliMe",
|
|
89808
89816
|
"getCliUserSettings",
|
|
89809
89817
|
"listCliOrganizations",
|
|
@@ -89814,6 +89822,14 @@ const implementedCommandOperationIds = /* @__PURE__ */ new Set([
|
|
|
89814
89822
|
"createCliModelChatExecution"
|
|
89815
89823
|
]);
|
|
89816
89824
|
const releaseEnabledCommandOperationIds = /* @__PURE__ */ new Set([
|
|
89825
|
+
"listCliAgents",
|
|
89826
|
+
"getCliAgent",
|
|
89827
|
+
"listCliAgentTemplates",
|
|
89828
|
+
"createCliAgent",
|
|
89829
|
+
"updateCliAgent",
|
|
89830
|
+
"deleteCliAgent",
|
|
89831
|
+
"updateCliAgentStatus",
|
|
89832
|
+
"getCliAgentShare",
|
|
89817
89833
|
"getCliMe",
|
|
89818
89834
|
"getCliUserSettings",
|
|
89819
89835
|
"listCliOrganizations",
|
|
@@ -90634,14 +90650,14 @@ class InvalidAppUrlError extends Error {
|
|
|
90634
90650
|
this.rawValue = rawValue;
|
|
90635
90651
|
}
|
|
90636
90652
|
}
|
|
90637
|
-
function isRecord$
|
|
90653
|
+
function isRecord$1(value) {
|
|
90638
90654
|
return typeof value === "object" && value !== null;
|
|
90639
90655
|
}
|
|
90640
90656
|
function optionalString$1(value) {
|
|
90641
90657
|
return typeof value === "string" ? value : void 0;
|
|
90642
90658
|
}
|
|
90643
90659
|
function parseCurrentOrganization(value) {
|
|
90644
|
-
if (!isRecord$
|
|
90660
|
+
if (!isRecord$1(value)) {
|
|
90645
90661
|
return void 0;
|
|
90646
90662
|
}
|
|
90647
90663
|
const id = optionalString$1(value["id"]);
|
|
@@ -90653,7 +90669,7 @@ function parseCurrentOrganization(value) {
|
|
|
90653
90669
|
return { id, slug, name };
|
|
90654
90670
|
}
|
|
90655
90671
|
function normalizeLoadedConfig(value) {
|
|
90656
|
-
if (!isRecord$
|
|
90672
|
+
if (!isRecord$1(value)) {
|
|
90657
90673
|
return {};
|
|
90658
90674
|
}
|
|
90659
90675
|
return {
|
|
@@ -92887,11 +92903,11 @@ const CREDENTIALS_FILE = path__namespace.join(CONFIG_DIR$1, "credentials.json");
|
|
|
92887
92903
|
const CREDENTIALS_LOCK_FILE = path__namespace.join(CONFIG_DIR$1, "credentials.lock");
|
|
92888
92904
|
class CredentialServiceTag extends Tag$1("CredentialService")() {
|
|
92889
92905
|
}
|
|
92890
|
-
function isNonEmptyString
|
|
92906
|
+
function isNonEmptyString(value) {
|
|
92891
92907
|
return typeof value === "string" && value.length > 0;
|
|
92892
92908
|
}
|
|
92893
92909
|
function hasOAuthClient(credentials) {
|
|
92894
|
-
return isNonEmptyString
|
|
92910
|
+
return isNonEmptyString(credentials?.clientId);
|
|
92895
92911
|
}
|
|
92896
92912
|
function isAccessTokenExpired(credentials, bufferMs = 0, now = Date.now()) {
|
|
92897
92913
|
if (!credentials?.expiresAt) {
|
|
@@ -92900,13 +92916,13 @@ function isAccessTokenExpired(credentials, bufferMs = 0, now = Date.now()) {
|
|
|
92900
92916
|
return credentials.expiresAt - bufferMs <= now;
|
|
92901
92917
|
}
|
|
92902
92918
|
function hasValidRefreshToken(credentials, now) {
|
|
92903
|
-
return isNonEmptyString
|
|
92919
|
+
return isNonEmptyString(credentials.refreshToken) && (credentials.refreshExpiresAt === void 0 || credentials.refreshExpiresAt > now);
|
|
92904
92920
|
}
|
|
92905
92921
|
function getCredentialAuthStatus(credentials, now = Date.now(), options = {}) {
|
|
92906
92922
|
if (!hasOAuthClient(credentials)) {
|
|
92907
92923
|
return "missing";
|
|
92908
92924
|
}
|
|
92909
|
-
const needsAccessRefresh = options.forceRefresh || !isNonEmptyString
|
|
92925
|
+
const needsAccessRefresh = options.forceRefresh || !isNonEmptyString(credentials.accessToken) || isAccessTokenExpired(credentials, options.accessExpiryBufferMs ?? 0, now);
|
|
92910
92926
|
if (!needsAccessRefresh) {
|
|
92911
92927
|
return "authenticated";
|
|
92912
92928
|
}
|
|
@@ -93902,7 +93918,7 @@ function trimTrailingSlash(value) {
|
|
|
93902
93918
|
function toError$1(error, fallbackMessage) {
|
|
93903
93919
|
return error instanceof Error ? new Error(maskSensitiveText(error.message)) : new Error(maskSensitiveText(fallbackMessage));
|
|
93904
93920
|
}
|
|
93905
|
-
function isRecord
|
|
93921
|
+
function isRecord(value) {
|
|
93906
93922
|
return typeof value === "object" && value !== null;
|
|
93907
93923
|
}
|
|
93908
93924
|
function optionalString(value) {
|
|
@@ -93912,7 +93928,7 @@ function optionalNumber(value) {
|
|
|
93912
93928
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
93913
93929
|
}
|
|
93914
93930
|
function parseOAuthTokenResponse(value) {
|
|
93915
|
-
if (!isRecord
|
|
93931
|
+
if (!isRecord(value)) {
|
|
93916
93932
|
throw new OAuthRequestError("OAuth token response was not a JSON object", void 0, "invalid_token_response");
|
|
93917
93933
|
}
|
|
93918
93934
|
const accessToken = optionalString(value["access_token"]);
|
|
@@ -94441,55 +94457,6 @@ async function acquire() {
|
|
|
94441
94457
|
}
|
|
94442
94458
|
}
|
|
94443
94459
|
|
|
94444
|
-
const SERVER_CAPABILITY_SCHEMA_VERSION = 1;
|
|
94445
|
-
class ServerCapabilityError extends Error {
|
|
94446
|
-
code;
|
|
94447
|
-
constructor(code, message) {
|
|
94448
|
-
super(message);
|
|
94449
|
-
this.name = "ServerCapabilityError";
|
|
94450
|
-
this.code = code;
|
|
94451
|
-
}
|
|
94452
|
-
}
|
|
94453
|
-
function parseEnabledServerOperations(value) {
|
|
94454
|
-
if (!isRecord(value) || value["schemaVersion"] !== SERVER_CAPABILITY_SCHEMA_VERSION) {
|
|
94455
|
-
throw new ServerCapabilityError(
|
|
94456
|
-
"CLI_CAPABILITIES_INCOMPATIBLE",
|
|
94457
|
-
"The server returned an unsupported CLI capability schema."
|
|
94458
|
-
);
|
|
94459
|
-
}
|
|
94460
|
-
const enabledOperations = value["enabledOperations"];
|
|
94461
|
-
if (!Array.isArray(enabledOperations)) {
|
|
94462
|
-
throw new ServerCapabilityError(
|
|
94463
|
-
"CLI_CAPABILITIES_INCOMPATIBLE",
|
|
94464
|
-
"The server returned an invalid CLI capability operation list."
|
|
94465
|
-
);
|
|
94466
|
-
}
|
|
94467
|
-
const operationIds = /* @__PURE__ */ new Set();
|
|
94468
|
-
for (const operation of enabledOperations) {
|
|
94469
|
-
if (!isRecord(operation) || !isNonEmptyString(operation["operationId"]) || !isNonEmptyString(operation["capability"]) || operationIds.has(operation["operationId"])) {
|
|
94470
|
-
throw new ServerCapabilityError(
|
|
94471
|
-
"CLI_CAPABILITIES_INCOMPATIBLE",
|
|
94472
|
-
"The server returned an invalid CLI capability operation."
|
|
94473
|
-
);
|
|
94474
|
-
}
|
|
94475
|
-
operationIds.add(operation["operationId"]);
|
|
94476
|
-
}
|
|
94477
|
-
return operationIds;
|
|
94478
|
-
}
|
|
94479
|
-
function requireEnabledServerOperation(enabledOperations, operationId) {
|
|
94480
|
-
if (enabledOperations.has(operationId)) return;
|
|
94481
|
-
throw new ServerCapabilityError(
|
|
94482
|
-
"CLI_OPERATION_NOT_ENABLED",
|
|
94483
|
-
`CLI operation "${operationId}" is not enabled by the server.`
|
|
94484
|
-
);
|
|
94485
|
-
}
|
|
94486
|
-
function isRecord(value) {
|
|
94487
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
94488
|
-
}
|
|
94489
|
-
function isNonEmptyString(value) {
|
|
94490
|
-
return typeof value === "string" && value.length > 0;
|
|
94491
|
-
}
|
|
94492
|
-
|
|
94493
94460
|
class ApiError extends TaggedError$1("ApiError") {
|
|
94494
94461
|
}
|
|
94495
94462
|
class NotLoggedInError extends TaggedError$1("NotLoggedInError") {
|
|
@@ -94654,26 +94621,31 @@ async function toApiError(response) {
|
|
|
94654
94621
|
errorData = await response.json();
|
|
94655
94622
|
} catch {
|
|
94656
94623
|
}
|
|
94657
|
-
const
|
|
94658
|
-
const
|
|
94624
|
+
const code = errorData.code ?? errorData.errorCode;
|
|
94625
|
+
const details = isCliQuotaErrorCode(code) ? parseCliQuotaErrorDetails(errorData.details, code) : void 0;
|
|
94626
|
+
const retryAfterSeconds = details ? details.limitKind === "concurrent" ? void 0 : details.retryAfterSeconds ?? parseRetryAfterSeconds(response.headers.get("retry-after")) : void 0;
|
|
94659
94627
|
return createApiError({
|
|
94660
94628
|
message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
94661
94629
|
statusCode: response.status,
|
|
94662
|
-
code
|
|
94630
|
+
code,
|
|
94663
94631
|
...details ? { details } : {},
|
|
94664
94632
|
...retryAfterSeconds === void 0 ? {} : { retryAfterSeconds }
|
|
94665
94633
|
});
|
|
94666
94634
|
}
|
|
94667
94635
|
function isCliQuotaErrorCode(code) {
|
|
94668
|
-
return code === "CLI_QUOTA_EXCEEDED" || code === "CLI_QUOTA_POLICY_UNAVAILABLE" || code === "CLI_QUOTA_LIMITER_UNAVAILABLE";
|
|
94636
|
+
return code === "CLI_QUOTA_EXCEEDED" || code === "CLI_QUOTA_POLICY_UNAVAILABLE" || code === "CLI_QUOTA_LIMITER_UNAVAILABLE" || code === "CLI_TEXT_DAILY_LIMIT" || code === "CLI_TEXT_USER_CONCURRENCY_LIMIT" || code === "CLI_TEXT_ORGANIZATION_CONCURRENCY_LIMIT";
|
|
94637
|
+
}
|
|
94638
|
+
function isCliTextQuotaErrorCode(code) {
|
|
94639
|
+
return code === "CLI_TEXT_DAILY_LIMIT" || code === "CLI_TEXT_USER_CONCURRENCY_LIMIT" || code === "CLI_TEXT_ORGANIZATION_CONCURRENCY_LIMIT";
|
|
94669
94640
|
}
|
|
94670
|
-
function parseCliQuotaErrorDetails(value) {
|
|
94641
|
+
function parseCliQuotaErrorDetails(value, code) {
|
|
94671
94642
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
94672
94643
|
const details = value;
|
|
94673
|
-
|
|
94674
|
-
|
|
94675
|
-
|
|
94676
|
-
|
|
94644
|
+
const sourceLimitKind = details["limitKind"];
|
|
94645
|
+
const limitKind = sourceLimitKind === "request_rate" ? "request_rate" : sourceLimitKind === "dailyTextAdmissions" ? "daily" : sourceLimitKind === "concurrentTextExecutions" ? "concurrent" : void 0;
|
|
94646
|
+
if (!limitKind) return void 0;
|
|
94647
|
+
const quotaClass = details["quotaClass"] ?? (isCliTextQuotaErrorCode(code) ? "text-execution" : void 0);
|
|
94648
|
+
if (typeof quotaClass !== "string" || !["bootstrap", "metadata", "text-execution", "control-read"].includes(quotaClass)) return void 0;
|
|
94677
94649
|
if (typeof details["requestId"] !== "string" || details["requestId"].length === 0) return void 0;
|
|
94678
94650
|
const scope = details["scope"];
|
|
94679
94651
|
if (scope !== void 0 && (typeof scope !== "string" || !["user", "organization", "bootstrap", "control-read"].includes(scope))) {
|
|
@@ -94683,17 +94655,42 @@ function parseCliQuotaErrorDetails(value) {
|
|
|
94683
94655
|
if (resetAt !== void 0 && (typeof resetAt !== "string" || !Number.isFinite(Date.parse(resetAt)))) {
|
|
94684
94656
|
return void 0;
|
|
94685
94657
|
}
|
|
94658
|
+
const retryAfterSeconds = details["retryAfterSeconds"];
|
|
94659
|
+
if (retryAfterSeconds !== void 0 && (typeof retryAfterSeconds !== "number" || !Number.isSafeInteger(retryAfterSeconds) || retryAfterSeconds < 0)) {
|
|
94660
|
+
return void 0;
|
|
94661
|
+
}
|
|
94686
94662
|
const dependency = details["dependency"];
|
|
94687
94663
|
if (dependency !== void 0 && dependency !== "policy" && dependency !== "limiter") return void 0;
|
|
94664
|
+
if (!isCliQuotaCombinationValid(code, limitKind, quotaClass, scope, dependency)) return void 0;
|
|
94688
94665
|
return {
|
|
94689
|
-
limitKind
|
|
94690
|
-
quotaClass
|
|
94666
|
+
limitKind,
|
|
94667
|
+
quotaClass,
|
|
94691
94668
|
requestId: details["requestId"],
|
|
94692
94669
|
...scope === void 0 ? {} : { scope },
|
|
94693
|
-
...resetAt === void 0 ? {} : { resetAt },
|
|
94670
|
+
...resetAt === void 0 || limitKind === "concurrent" ? {} : { resetAt },
|
|
94671
|
+
...retryAfterSeconds === void 0 || limitKind === "concurrent" ? {} : { retryAfterSeconds },
|
|
94694
94672
|
...dependency === void 0 ? {} : { dependency }
|
|
94695
94673
|
};
|
|
94696
94674
|
}
|
|
94675
|
+
function isCliQuotaCombinationValid(code, limitKind, quotaClass, scope, dependency) {
|
|
94676
|
+
if (isCliTextQuotaErrorCode(code)) {
|
|
94677
|
+
const expectedLimitKind = code === "CLI_TEXT_DAILY_LIMIT" ? "daily" : "concurrent";
|
|
94678
|
+
const expectedScope = code === "CLI_TEXT_ORGANIZATION_CONCURRENCY_LIMIT" ? "organization" : "user";
|
|
94679
|
+
return limitKind === expectedLimitKind && quotaClass === "text-execution" && scope === expectedScope && dependency === void 0;
|
|
94680
|
+
}
|
|
94681
|
+
if (limitKind !== "request_rate") return false;
|
|
94682
|
+
const validScope = scope === void 0 || (quotaClass === "bootstrap" ? scope === "bootstrap" : quotaClass === "control-read" ? scope === "control-read" : scope === "user" || scope === "organization");
|
|
94683
|
+
if (!validScope) return false;
|
|
94684
|
+
switch (code) {
|
|
94685
|
+
case "CLI_QUOTA_EXCEEDED":
|
|
94686
|
+
return dependency === void 0;
|
|
94687
|
+
case "CLI_QUOTA_POLICY_UNAVAILABLE":
|
|
94688
|
+
return dependency === void 0 || dependency === "policy";
|
|
94689
|
+
case "CLI_QUOTA_LIMITER_UNAVAILABLE":
|
|
94690
|
+
return dependency === void 0 || dependency === "limiter";
|
|
94691
|
+
}
|
|
94692
|
+
return false;
|
|
94693
|
+
}
|
|
94697
94694
|
function parseRetryAfterSeconds(value) {
|
|
94698
94695
|
if (!value || !/^\d+$/.test(value)) return void 0;
|
|
94699
94696
|
const parsed = Number(value);
|
|
@@ -94952,7 +94949,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
94952
94949
|
});
|
|
94953
94950
|
const baseUrl = () => loadConfiguredApiBaseUrl();
|
|
94954
94951
|
const chatBaseUrl = () => loadConfiguredChatBaseUrl();
|
|
94955
|
-
const
|
|
94952
|
+
const requireReleaseEnabledOperation = (operationId) => {
|
|
94956
94953
|
if (buildEnv !== "prod") return _void;
|
|
94957
94954
|
if (!releaseEnabledCommandOperationIds.has(operationId)) {
|
|
94958
94955
|
return fail$3(createApiError({
|
|
@@ -94961,24 +94958,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
94961
94958
|
code: "CLI_OPERATION_NOT_ENABLED"
|
|
94962
94959
|
}));
|
|
94963
94960
|
}
|
|
94964
|
-
return
|
|
94965
|
-
const response = yield* makeRequest(
|
|
94966
|
-
baseUrl,
|
|
94967
|
-
"/api/cli/v1/capabilities",
|
|
94968
|
-
token
|
|
94969
|
-
);
|
|
94970
|
-
yield* try_({
|
|
94971
|
-
try: () => {
|
|
94972
|
-
const enabledOperations = parseEnabledServerOperations(response);
|
|
94973
|
-
requireEnabledServerOperation(enabledOperations, operationId);
|
|
94974
|
-
},
|
|
94975
|
-
catch: (error) => createApiError({
|
|
94976
|
-
message: error instanceof Error ? error.message : "CLI server capability validation failed",
|
|
94977
|
-
statusCode: error instanceof ServerCapabilityError && error.code === "CLI_OPERATION_NOT_ENABLED" ? 404 : 503,
|
|
94978
|
-
code: error instanceof ServerCapabilityError ? error.code : "CLI_CAPABILITIES_INCOMPATIBLE"
|
|
94979
|
-
})
|
|
94980
|
-
});
|
|
94981
|
-
});
|
|
94961
|
+
return _void;
|
|
94982
94962
|
};
|
|
94983
94963
|
const subscribeAgentChatStream = (orgSlug, conversationId, token) => gen(function* () {
|
|
94984
94964
|
const resolvedChatBaseUrl = yield* requireChatBaseUrlEffect();
|
|
@@ -95046,12 +95026,12 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95046
95026
|
return {
|
|
95047
95027
|
listOrganizations: () => gen(function* () {
|
|
95048
95028
|
const token = yield* getAccessToken();
|
|
95049
|
-
yield*
|
|
95029
|
+
yield* requireReleaseEnabledOperation("listCliOrganizations");
|
|
95050
95030
|
return yield* makeRequest(baseUrl, "/api/cli/v1/organizations", token);
|
|
95051
95031
|
}),
|
|
95052
95032
|
getOrganization: (slug) => gen(function* () {
|
|
95053
95033
|
const token = yield* getAccessToken();
|
|
95054
|
-
yield*
|
|
95034
|
+
yield* requireReleaseEnabledOperation("listCliOrganizations");
|
|
95055
95035
|
const orgs = yield* makeRequest(baseUrl, "/api/cli/v1/organizations", token);
|
|
95056
95036
|
const org = orgs.find((o) => o.slug === slug);
|
|
95057
95037
|
if (!org) {
|
|
@@ -95291,7 +95271,8 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95291
95271
|
// Phase 2: Agent management
|
|
95292
95272
|
listInstalledAgents: (orgSlug) => gen(function* () {
|
|
95293
95273
|
const token = yield* getAccessToken();
|
|
95294
|
-
|
|
95274
|
+
yield* requireReleaseEnabledOperation("listCliAgents");
|
|
95275
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents`;
|
|
95295
95276
|
const raw = yield* makeRequest(baseUrl, path, token);
|
|
95296
95277
|
return {
|
|
95297
95278
|
pagination: normalizePageNumberPagination(raw.pagination, raw.list.length),
|
|
@@ -95300,7 +95281,8 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95300
95281
|
}),
|
|
95301
95282
|
getInstalledAgent: (orgSlug, agentId) => gen(function* () {
|
|
95302
95283
|
const token = yield* getAccessToken();
|
|
95303
|
-
|
|
95284
|
+
yield* requireReleaseEnabledOperation("getCliAgent");
|
|
95285
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}`;
|
|
95304
95286
|
const raw = yield* makeRequest(baseUrl, path, token);
|
|
95305
95287
|
return {
|
|
95306
95288
|
data: {
|
|
@@ -95312,7 +95294,8 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95312
95294
|
}),
|
|
95313
95295
|
updateInstalledAgentStatus: (orgSlug, agentId, status) => gen(function* () {
|
|
95314
95296
|
const token = yield* getAccessToken();
|
|
95315
|
-
|
|
95297
|
+
yield* requireReleaseEnabledOperation("updateCliAgentStatus");
|
|
95298
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}/status`;
|
|
95316
95299
|
return yield* makeRequest(baseUrl, path, token, {
|
|
95317
95300
|
method: "PATCH",
|
|
95318
95301
|
body: { status }
|
|
@@ -95391,7 +95374,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95391
95374
|
// Phase 4: Monitoring
|
|
95392
95375
|
listOrgMembers: (orgSlug) => gen(function* () {
|
|
95393
95376
|
const token = yield* getAccessToken();
|
|
95394
|
-
yield*
|
|
95377
|
+
yield* requireReleaseEnabledOperation("listCliOrganizationMembers");
|
|
95395
95378
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/members`;
|
|
95396
95379
|
const raw = yield* makeRequest(baseUrl, path, token);
|
|
95397
95380
|
return {
|
|
@@ -95407,7 +95390,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95407
95390
|
listModels: (orgSlug) => gen(function* () {
|
|
95408
95391
|
yield* requireChatBaseUrlEffect();
|
|
95409
95392
|
const token = yield* getAccessToken();
|
|
95410
|
-
yield*
|
|
95393
|
+
yield* requireReleaseEnabledOperation("listCliModels");
|
|
95411
95394
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/models`;
|
|
95412
95395
|
const response = yield* makeRequest(chatBaseUrl, path, token);
|
|
95413
95396
|
return response.models.map((id) => ({
|
|
@@ -95418,14 +95401,14 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95418
95401
|
listModelExecModels: (orgSlug) => gen(function* () {
|
|
95419
95402
|
yield* requireChatBaseUrlEffect();
|
|
95420
95403
|
const token = yield* getAccessToken();
|
|
95421
|
-
yield*
|
|
95404
|
+
yield* requireReleaseEnabledOperation("listCliModelExecModels");
|
|
95422
95405
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/model-exec/models`;
|
|
95423
95406
|
return yield* makeRequest(chatBaseUrl, path, token);
|
|
95424
95407
|
}),
|
|
95425
95408
|
executeModelExecChat: (orgSlug, body) => gen(function* () {
|
|
95426
95409
|
yield* requireChatBaseUrlEffect();
|
|
95427
95410
|
const token = yield* getAccessToken();
|
|
95428
|
-
yield*
|
|
95411
|
+
yield* requireReleaseEnabledOperation("createCliModelChatExecution");
|
|
95429
95412
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/model-exec/chat`;
|
|
95430
95413
|
return yield* makeRequest(chatBaseUrl, path, token, {
|
|
95431
95414
|
method: "POST",
|
|
@@ -95567,7 +95550,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95567
95550
|
// Phase 6: Auth enhancements
|
|
95568
95551
|
getMe: () => gen(function* () {
|
|
95569
95552
|
const token = yield* getAccessToken();
|
|
95570
|
-
yield*
|
|
95553
|
+
yield* requireReleaseEnabledOperation("getCliMe");
|
|
95571
95554
|
return yield* makeRequest(baseUrl, "/api/cli/v1/me", token);
|
|
95572
95555
|
}),
|
|
95573
95556
|
refreshToken: () => refreshAccessToken({ force: true }),
|
|
@@ -95605,7 +95588,8 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95605
95588
|
// Phase 8: Agent admin CRUD
|
|
95606
95589
|
createInstalledAgent: (orgSlug, body) => gen(function* () {
|
|
95607
95590
|
const token = yield* getAccessToken();
|
|
95608
|
-
|
|
95591
|
+
yield* requireReleaseEnabledOperation("createCliAgent");
|
|
95592
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents`;
|
|
95609
95593
|
return yield* makeRequest(baseUrl, path, token, {
|
|
95610
95594
|
method: "POST",
|
|
95611
95595
|
body
|
|
@@ -95613,7 +95597,8 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95613
95597
|
}),
|
|
95614
95598
|
updateInstalledAgent: (orgSlug, agentId, body) => gen(function* () {
|
|
95615
95599
|
const token = yield* getAccessToken();
|
|
95616
|
-
|
|
95600
|
+
yield* requireReleaseEnabledOperation("updateCliAgent");
|
|
95601
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}`;
|
|
95617
95602
|
return yield* makeRequest(baseUrl, path, token, {
|
|
95618
95603
|
method: "PATCH",
|
|
95619
95604
|
body
|
|
@@ -95621,7 +95606,8 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95621
95606
|
}),
|
|
95622
95607
|
deleteInstalledAgent: (orgSlug, agentId) => gen(function* () {
|
|
95623
95608
|
const token = yield* getAccessToken();
|
|
95624
|
-
|
|
95609
|
+
yield* requireReleaseEnabledOperation("deleteCliAgent");
|
|
95610
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}`;
|
|
95625
95611
|
return yield* makeRequest(baseUrl, path, token, { method: "DELETE" });
|
|
95626
95612
|
}),
|
|
95627
95613
|
exportInstalledAgent: (orgSlug, agentId) => gen(function* () {
|
|
@@ -95647,7 +95633,8 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95647
95633
|
}),
|
|
95648
95634
|
getInstalledAgentShare: (orgSlug, agentId) => gen(function* () {
|
|
95649
95635
|
const token = yield* getAccessToken();
|
|
95650
|
-
|
|
95636
|
+
yield* requireReleaseEnabledOperation("getCliAgentShare");
|
|
95637
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}/share`;
|
|
95651
95638
|
const raw = yield* makeRequest(baseUrl, path, token);
|
|
95652
95639
|
const sharedUserList = yield* try_({
|
|
95653
95640
|
try: () => normalizeSharedUserList(raw.sharedUserList),
|
|
@@ -95660,11 +95647,19 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95660
95647
|
}),
|
|
95661
95648
|
listAgentTemplates: (orgSlug) => gen(function* () {
|
|
95662
95649
|
const token = yield* getAccessToken();
|
|
95663
|
-
|
|
95664
|
-
const
|
|
95650
|
+
yield* requireReleaseEnabledOperation("listCliAgentTemplates");
|
|
95651
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/templates`;
|
|
95652
|
+
const templates = [];
|
|
95653
|
+
let page = 1;
|
|
95654
|
+
while (true) {
|
|
95655
|
+
const raw = yield* makeRequest(baseUrl, page === 1 ? path : `${path}?page=${page}`, token);
|
|
95656
|
+
templates.push(...raw.list);
|
|
95657
|
+
if (raw.list.length === 0 || page * raw.pagination.pageSize >= raw.pagination.total) break;
|
|
95658
|
+
page += 1;
|
|
95659
|
+
}
|
|
95665
95660
|
return {
|
|
95666
|
-
pagination: { pageNumber: 1, pageSize:
|
|
95667
|
-
data:
|
|
95661
|
+
pagination: { pageNumber: 1, pageSize: templates.length, totalCount: templates.length },
|
|
95662
|
+
data: templates.map((item) => ({
|
|
95668
95663
|
id: item.agentId,
|
|
95669
95664
|
displayName: item.label,
|
|
95670
95665
|
categories: item.categoryList,
|
|
@@ -95749,13 +95744,13 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95749
95744
|
// Org capabilities & user settings
|
|
95750
95745
|
getOrgCapabilities: (orgSlug) => gen(function* () {
|
|
95751
95746
|
const token = yield* getAccessToken();
|
|
95752
|
-
yield*
|
|
95747
|
+
yield* requireReleaseEnabledOperation("getCliOrganizationCapabilities");
|
|
95753
95748
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/capabilities`;
|
|
95754
95749
|
return yield* makeRequest(baseUrl, path, token);
|
|
95755
95750
|
}),
|
|
95756
95751
|
getUserSettings: () => gen(function* () {
|
|
95757
95752
|
const token = yield* getAccessToken();
|
|
95758
|
-
yield*
|
|
95753
|
+
yield* requireReleaseEnabledOperation("getCliUserSettings");
|
|
95759
95754
|
return yield* makeRequest(baseUrl, "/api/cli/v1/me/settings", token);
|
|
95760
95755
|
}),
|
|
95761
95756
|
// Tunnel management
|
|
@@ -49,8 +49,9 @@
|
|
|
49
49
|
| SKILL-04 | skill-admin | `aipctl admin skill list`, `get`, `delete`, `publish`, `unpublish` | `listAdminSkills`, `getAdminSkill`, `deleteAdminSkill`, `updateAdminSkill` | api | `GET`, `GET`, `DELETE`, `PATCH` | `/api/web/admin/organizations/slug/{organizationSlug}/skills`; `/skills/{skillId}` | list query `{ pageNumber,pageSize,search }`; publish toggle body `{ availableInLibrary: boolean }` | local `ListAdminSkillsResponse`, `SkillDetail`, `void` | `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"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/skills/{skillId}"]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/admin/skill.test.ts`; needed admin list/detail/update path snapshot |
|
|
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
|
-
| P0-AGENT-01 | agent-user | `aipctl agent list`, `aipctl agent get` | `listInstalledAgents`, `getInstalledAgent` | api | `GET`, `GET` | `/api/
|
|
53
|
-
| P0-AGENT-02 | agent-admin | `aipctl admin agent create`, `update`, `delete`, `
|
|
52
|
+
| P0-AGENT-01 | agent-user | `aipctl agent list`, `aipctl agent get` | `listInstalledAgents`, `getInstalledAgent` | api | `GET`, `GET` | `/api/cli/v1/organizations/{organizationSlug}/agents`; `/{installedAgentId}` | preserves user read semantics and maps `list`/`installedAgentId` to local `data`/`id` | local `ListInstalledAgentsResponse`, `{ data: InstalledAgentDetail }` | `resource/oas/modules/backend/cli/openapi.yaml`; shared DTO refs from `resource/oas/duplo.yaml` | `backend/api/.../cli/generated/api/CliAgentApi.kt` | `generated-ready` | `P0` | `migrate` | none; dedicated adapter delegates to the working `AgentsApiController` bean | `AI-6344` | `src/core/api.test.ts`, `CliAgentApiControllerTest`, Gateway registry/admission parity; real local production CLI list/get JSON |
|
|
53
|
+
| P0-AGENT-02 | agent-admin | `aipctl admin agent create`, `update`, `delete`, `share`, `templates`; `aipctl agent enable`, `disable` | `createInstalledAgent`, `updateInstalledAgent`, `deleteInstalledAgent`, `getInstalledAgentShare`, `listAgentTemplates`, `updateInstalledAgentStatus` | api | `POST`, `PATCH`, `DELETE`, `GET`, `GET`, `PATCH` | `/api/cli/v1/organizations/{organizationSlug}/agents`; `/{installedAgentId}`; `/{installedAgentId}/share`; `/templates`; `/{installedAgentId}/status` | existing create/update/status bodies; templates collect bounded pages and retain the full catalog; share is read-only | create/update `{ id }`, void mutation responses, existing CLI template/share mapping | `resource/oas/modules/backend/cli/openapi.yaml`; shared legacy DTO refs | `backend/api/.../cli/generated/api/CliAgentApi.kt` | `generated-ready` | `P0` | `migrate` | none; AI operator/workflow/audit policy stays in existing domain owner | `AI-6344` | all eight operations capability/path tests, mutation non-replay, template paging, real CLI lifecycle/DB/audit and metadata 429 verification |
|
|
54
|
+
| P0-AGENT-03 | agent-export | `aipctl admin agent export` (GA-CANDIDATE, production gated) | `exportInstalledAgent` | api | `GET` | `/web/admin/organizations/slug/{organizationSlug}/installed-agents/{installedAgentId}/export` | existing direct controller request | YAML `Buffer` | `backend/api/.../app/controller/AgentExportController.kt`; intentionally OAS-codegen excluded | none | `legacy-generated` | `P0` | `legacy-exception` | owner=`AgentExportController`; dedicated transfer contract, size/timeout/partial-file/authorization/audit gates remain | `AI-6380` | existing direct export path/Buffer/404 tests; production help remains hidden |
|
|
54
55
|
| 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
56
|
| 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
57
|
| 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 |
|
|
@@ -67,15 +68,18 @@
|
|
|
67
68
|
|
|
68
69
|
## 공통 CLI request quota 오류 계약
|
|
69
70
|
|
|
70
|
-
`GA-DIRECT` 업무 호출과 `GET /api/cli/v1/capabilities`는 Gateway request-rate admission을 통과한다. Gateway-owned source 계약은 `resource/oas/modules/backend-gateway/me/components/schemas/CliQuotaErrorResponse.yaml`과 `CliQuotaErrorDetails.yaml`이다.
|
|
71
|
+
`GA-DIRECT` 업무 호출과 명시적 discovery/진단용 `GET /api/cli/v1/capabilities`는 각각 Gateway request-rate admission을 통과한다. production CLI는 업무마다 capability를 선조회하지 않는다. 로컬 release manifest는 artifact에 없는 명령을 차단하고, 실제 업무 endpoint의 Gateway registry가 최신 server release/rollout/quota를 authoritative하게 검사한다. Gateway-owned source 계약은 `resource/oas/modules/backend-gateway/me/components/schemas/CliQuotaErrorResponse.yaml`과 `CliQuotaErrorDetails.yaml`이다.
|
|
71
72
|
|
|
72
73
|
| HTTP | code | CLI 처리 |
|
|
73
74
|
| --- | --- | --- |
|
|
74
75
|
| 429 | `CLI_QUOTA_EXCEEDED` | `limitKind=request_rate`, quota class, denying scope, request ID를 보존한다. 양수 refill로 계산 가능한 경우에만 `Retry-After`, `resetAt`을 보존한다. 자동 retry는 하지 않는다. |
|
|
75
76
|
| 503 | `CLI_QUOTA_POLICY_UNAVAILABLE` | Backend effective-policy auth/timeout/schema/freshness 실패. stale/default policy로 대체하거나 자동 retry하지 않는다. |
|
|
76
77
|
| 503 | `CLI_QUOTA_LIMITER_UNAVAILABLE` | Redis timeout/script/result 실패. 유료·mutation 요청을 자동 retry하지 않는다. |
|
|
78
|
+
| 429 | `CLI_TEXT_DAILY_LIMIT` | `limitKind=daily`, `quotaClass=text-execution`, 사용자 scope와 request ID를 보존한다. 유효한 UTC reset 시각과 그 시각에서 계산한 retry만 노출하며 자동 retry하지 않는다. |
|
|
79
|
+
| 429 | `CLI_TEXT_USER_CONCURRENCY_LIMIT` | `limitKind=concurrent`, `quotaClass=text-execution`, 사용자 scope와 request ID만 보존한다. permit 해제 시각을 알 수 없으므로 `Retry-After`와 `resetAt`을 만들거나 전달하지 않는다. |
|
|
80
|
+
| 429 | `CLI_TEXT_ORGANIZATION_CONCURRENCY_LIMIT` | `limitKind=concurrent`, `quotaClass=text-execution`, 조직 scope와 request ID만 보존한다. permit 해제 시각을 알 수 없으므로 `Retry-After`와 `resetAt`을 만들거나 전달하지 않는다. |
|
|
77
81
|
|
|
78
|
-
CLI `ApiError`는 위
|
|
82
|
+
CLI `ApiError`는 위 여섯 code에서 allowlist된 quota detail만 보존하며 서버가 추가로 보낸 조직/사용자 ID, raw policy, Redis key는 노출하지 않는다. Gateway는 `code`, Chat은 `errorCode`를 사용하지만 CLI에서 같은 진단 구조로 정규화한다. 회귀 테스트는 `src/core/api.test.ts`, Chat `cli-text-execution.internal.service.spec.ts`, Gateway `test/cli/quota/**`에 있다.
|
|
79
83
|
|
|
80
84
|
## Queue IDs for follow-up
|
|
81
85
|
|
|
@@ -83,8 +87,8 @@ CLI `ApiError`는 위 세 code에서 allowlist된 quota detail만 보존하며
|
|
|
83
87
|
|
|
84
88
|
- `P0-ORG-01` org member list/mutation legacy-exception aligned (done in `AIP-PUB-04`, independent contract follow-up remains)
|
|
85
89
|
- `P0-ORG-02` org invite-link trio hidden from public beta (done in `AIP-PUB-04`)
|
|
86
|
-
- `P0-AGENT-01`
|
|
87
|
-
- `P0-AGENT-
|
|
90
|
+
- `P0-AGENT-01` / `P0-AGENT-02` moved to dedicated CLI lifecycle endpoints with metadata quota and capability checks (`AI-6344`)
|
|
91
|
+
- `P0-AGENT-03` export remains a gated transfer candidate (`AI-6380`)
|
|
88
92
|
- `P0-DRIVE-01` drive list/download/delete/mkdir/rename/usage contract migration (done in `AIP-PUB-04`)
|
|
89
93
|
- `P0-DRIVE-02` drive upload contract migration (done in `AIP-PUB-04`)
|
|
90
94
|
- `P0-MODEL-01` model list path/DTO migration (done in `AIP-PUB-04`)
|
|
@@ -101,6 +105,6 @@ CLI `ApiError`는 위 세 code에서 allowlist된 quota detail만 보존하며
|
|
|
101
105
|
## Manual notes
|
|
102
106
|
|
|
103
107
|
- Generated reference files under `frontend/packages/api/src/out/**` are inventory links only. They are not imported by CLI source/build/test/lint.
|
|
104
|
-
-
|
|
108
|
+
- Agent lifecycle uses the dedicated `CliAgentApiController` and CLI OAS, delegating internally to the implemented `AgentsApiController` bean. Future v2 implementation can replace that internal owner without changing the CLI endpoint. `agent chat` and `admin agent export` retain their separate candidate gates.
|
|
105
109
|
- OAuth authorization-server metadata, dynamic client registration, authorize, and token endpoints used by `src/core/oauth.ts` were not found in current `resource/oas`; they need owner-backed contractization.
|
|
106
110
|
- `config` commands intentionally excluded. local config surface has no network owner.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aipctl",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.9",
|
|
4
4
|
"description": "QueryPie AIP and MCP CLI tool",
|
|
5
5
|
"author": "QueryPie",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"node": ">=24.18.0"
|
|
23
23
|
},
|
|
24
24
|
"metadata": {
|
|
25
|
-
"contentHash": "
|
|
26
|
-
"wrapperHash": "
|
|
25
|
+
"contentHash": "95bfb896d5e0e21910685b39eff86f3d35ee5c1b0ef28854912f78fdbc7bee58",
|
|
26
|
+
"wrapperHash": "a4ef2565f44cb9eb4a3706246f59427bf40a5275dc7bea030fb30024be6f5ab8",
|
|
27
27
|
"nativeHash": "006b08c3e391f4571d9b7c0f12d684fe2448106259e7e0581b10f9be362452e9"
|
|
28
28
|
},
|
|
29
29
|
"optionalDependencies": {
|