aipctl 2026.9.8 → 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 +73 -109
- package/docs/api-contract-inventory.md +5 -2
- 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
|
|
|
@@ -90650,14 +90650,14 @@ class InvalidAppUrlError extends Error {
|
|
|
90650
90650
|
this.rawValue = rawValue;
|
|
90651
90651
|
}
|
|
90652
90652
|
}
|
|
90653
|
-
function isRecord$
|
|
90653
|
+
function isRecord$1(value) {
|
|
90654
90654
|
return typeof value === "object" && value !== null;
|
|
90655
90655
|
}
|
|
90656
90656
|
function optionalString$1(value) {
|
|
90657
90657
|
return typeof value === "string" ? value : void 0;
|
|
90658
90658
|
}
|
|
90659
90659
|
function parseCurrentOrganization(value) {
|
|
90660
|
-
if (!isRecord$
|
|
90660
|
+
if (!isRecord$1(value)) {
|
|
90661
90661
|
return void 0;
|
|
90662
90662
|
}
|
|
90663
90663
|
const id = optionalString$1(value["id"]);
|
|
@@ -90669,7 +90669,7 @@ function parseCurrentOrganization(value) {
|
|
|
90669
90669
|
return { id, slug, name };
|
|
90670
90670
|
}
|
|
90671
90671
|
function normalizeLoadedConfig(value) {
|
|
90672
|
-
if (!isRecord$
|
|
90672
|
+
if (!isRecord$1(value)) {
|
|
90673
90673
|
return {};
|
|
90674
90674
|
}
|
|
90675
90675
|
return {
|
|
@@ -92903,11 +92903,11 @@ const CREDENTIALS_FILE = path__namespace.join(CONFIG_DIR$1, "credentials.json");
|
|
|
92903
92903
|
const CREDENTIALS_LOCK_FILE = path__namespace.join(CONFIG_DIR$1, "credentials.lock");
|
|
92904
92904
|
class CredentialServiceTag extends Tag$1("CredentialService")() {
|
|
92905
92905
|
}
|
|
92906
|
-
function isNonEmptyString
|
|
92906
|
+
function isNonEmptyString(value) {
|
|
92907
92907
|
return typeof value === "string" && value.length > 0;
|
|
92908
92908
|
}
|
|
92909
92909
|
function hasOAuthClient(credentials) {
|
|
92910
|
-
return isNonEmptyString
|
|
92910
|
+
return isNonEmptyString(credentials?.clientId);
|
|
92911
92911
|
}
|
|
92912
92912
|
function isAccessTokenExpired(credentials, bufferMs = 0, now = Date.now()) {
|
|
92913
92913
|
if (!credentials?.expiresAt) {
|
|
@@ -92916,13 +92916,13 @@ function isAccessTokenExpired(credentials, bufferMs = 0, now = Date.now()) {
|
|
|
92916
92916
|
return credentials.expiresAt - bufferMs <= now;
|
|
92917
92917
|
}
|
|
92918
92918
|
function hasValidRefreshToken(credentials, now) {
|
|
92919
|
-
return isNonEmptyString
|
|
92919
|
+
return isNonEmptyString(credentials.refreshToken) && (credentials.refreshExpiresAt === void 0 || credentials.refreshExpiresAt > now);
|
|
92920
92920
|
}
|
|
92921
92921
|
function getCredentialAuthStatus(credentials, now = Date.now(), options = {}) {
|
|
92922
92922
|
if (!hasOAuthClient(credentials)) {
|
|
92923
92923
|
return "missing";
|
|
92924
92924
|
}
|
|
92925
|
-
const needsAccessRefresh = options.forceRefresh || !isNonEmptyString
|
|
92925
|
+
const needsAccessRefresh = options.forceRefresh || !isNonEmptyString(credentials.accessToken) || isAccessTokenExpired(credentials, options.accessExpiryBufferMs ?? 0, now);
|
|
92926
92926
|
if (!needsAccessRefresh) {
|
|
92927
92927
|
return "authenticated";
|
|
92928
92928
|
}
|
|
@@ -93918,7 +93918,7 @@ function trimTrailingSlash(value) {
|
|
|
93918
93918
|
function toError$1(error, fallbackMessage) {
|
|
93919
93919
|
return error instanceof Error ? new Error(maskSensitiveText(error.message)) : new Error(maskSensitiveText(fallbackMessage));
|
|
93920
93920
|
}
|
|
93921
|
-
function isRecord
|
|
93921
|
+
function isRecord(value) {
|
|
93922
93922
|
return typeof value === "object" && value !== null;
|
|
93923
93923
|
}
|
|
93924
93924
|
function optionalString(value) {
|
|
@@ -93928,7 +93928,7 @@ function optionalNumber(value) {
|
|
|
93928
93928
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
93929
93929
|
}
|
|
93930
93930
|
function parseOAuthTokenResponse(value) {
|
|
93931
|
-
if (!isRecord
|
|
93931
|
+
if (!isRecord(value)) {
|
|
93932
93932
|
throw new OAuthRequestError("OAuth token response was not a JSON object", void 0, "invalid_token_response");
|
|
93933
93933
|
}
|
|
93934
93934
|
const accessToken = optionalString(value["access_token"]);
|
|
@@ -94457,55 +94457,6 @@ async function acquire() {
|
|
|
94457
94457
|
}
|
|
94458
94458
|
}
|
|
94459
94459
|
|
|
94460
|
-
const SERVER_CAPABILITY_SCHEMA_VERSION = 1;
|
|
94461
|
-
class ServerCapabilityError extends Error {
|
|
94462
|
-
code;
|
|
94463
|
-
constructor(code, message) {
|
|
94464
|
-
super(message);
|
|
94465
|
-
this.name = "ServerCapabilityError";
|
|
94466
|
-
this.code = code;
|
|
94467
|
-
}
|
|
94468
|
-
}
|
|
94469
|
-
function parseEnabledServerOperations(value) {
|
|
94470
|
-
if (!isRecord(value) || value["schemaVersion"] !== SERVER_CAPABILITY_SCHEMA_VERSION) {
|
|
94471
|
-
throw new ServerCapabilityError(
|
|
94472
|
-
"CLI_CAPABILITIES_INCOMPATIBLE",
|
|
94473
|
-
"The server returned an unsupported CLI capability schema."
|
|
94474
|
-
);
|
|
94475
|
-
}
|
|
94476
|
-
const enabledOperations = value["enabledOperations"];
|
|
94477
|
-
if (!Array.isArray(enabledOperations)) {
|
|
94478
|
-
throw new ServerCapabilityError(
|
|
94479
|
-
"CLI_CAPABILITIES_INCOMPATIBLE",
|
|
94480
|
-
"The server returned an invalid CLI capability operation list."
|
|
94481
|
-
);
|
|
94482
|
-
}
|
|
94483
|
-
const operationIds = /* @__PURE__ */ new Set();
|
|
94484
|
-
for (const operation of enabledOperations) {
|
|
94485
|
-
if (!isRecord(operation) || !isNonEmptyString(operation["operationId"]) || !isNonEmptyString(operation["capability"]) || operationIds.has(operation["operationId"])) {
|
|
94486
|
-
throw new ServerCapabilityError(
|
|
94487
|
-
"CLI_CAPABILITIES_INCOMPATIBLE",
|
|
94488
|
-
"The server returned an invalid CLI capability operation."
|
|
94489
|
-
);
|
|
94490
|
-
}
|
|
94491
|
-
operationIds.add(operation["operationId"]);
|
|
94492
|
-
}
|
|
94493
|
-
return operationIds;
|
|
94494
|
-
}
|
|
94495
|
-
function requireEnabledServerOperation(enabledOperations, operationId) {
|
|
94496
|
-
if (enabledOperations.has(operationId)) return;
|
|
94497
|
-
throw new ServerCapabilityError(
|
|
94498
|
-
"CLI_OPERATION_NOT_ENABLED",
|
|
94499
|
-
`CLI operation "${operationId}" is not enabled by the server.`
|
|
94500
|
-
);
|
|
94501
|
-
}
|
|
94502
|
-
function isRecord(value) {
|
|
94503
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
94504
|
-
}
|
|
94505
|
-
function isNonEmptyString(value) {
|
|
94506
|
-
return typeof value === "string" && value.length > 0;
|
|
94507
|
-
}
|
|
94508
|
-
|
|
94509
94460
|
class ApiError extends TaggedError$1("ApiError") {
|
|
94510
94461
|
}
|
|
94511
94462
|
class NotLoggedInError extends TaggedError$1("NotLoggedInError") {
|
|
@@ -94670,26 +94621,31 @@ async function toApiError(response) {
|
|
|
94670
94621
|
errorData = await response.json();
|
|
94671
94622
|
} catch {
|
|
94672
94623
|
}
|
|
94673
|
-
const
|
|
94674
|
-
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;
|
|
94675
94627
|
return createApiError({
|
|
94676
94628
|
message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
94677
94629
|
statusCode: response.status,
|
|
94678
|
-
code
|
|
94630
|
+
code,
|
|
94679
94631
|
...details ? { details } : {},
|
|
94680
94632
|
...retryAfterSeconds === void 0 ? {} : { retryAfterSeconds }
|
|
94681
94633
|
});
|
|
94682
94634
|
}
|
|
94683
94635
|
function isCliQuotaErrorCode(code) {
|
|
94684
|
-
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";
|
|
94685
94637
|
}
|
|
94686
|
-
function
|
|
94638
|
+
function isCliTextQuotaErrorCode(code) {
|
|
94639
|
+
return code === "CLI_TEXT_DAILY_LIMIT" || code === "CLI_TEXT_USER_CONCURRENCY_LIMIT" || code === "CLI_TEXT_ORGANIZATION_CONCURRENCY_LIMIT";
|
|
94640
|
+
}
|
|
94641
|
+
function parseCliQuotaErrorDetails(value, code) {
|
|
94687
94642
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
94688
94643
|
const details = value;
|
|
94689
|
-
|
|
94690
|
-
|
|
94691
|
-
|
|
94692
|
-
|
|
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;
|
|
94693
94649
|
if (typeof details["requestId"] !== "string" || details["requestId"].length === 0) return void 0;
|
|
94694
94650
|
const scope = details["scope"];
|
|
94695
94651
|
if (scope !== void 0 && (typeof scope !== "string" || !["user", "organization", "bootstrap", "control-read"].includes(scope))) {
|
|
@@ -94699,17 +94655,42 @@ function parseCliQuotaErrorDetails(value) {
|
|
|
94699
94655
|
if (resetAt !== void 0 && (typeof resetAt !== "string" || !Number.isFinite(Date.parse(resetAt)))) {
|
|
94700
94656
|
return void 0;
|
|
94701
94657
|
}
|
|
94658
|
+
const retryAfterSeconds = details["retryAfterSeconds"];
|
|
94659
|
+
if (retryAfterSeconds !== void 0 && (typeof retryAfterSeconds !== "number" || !Number.isSafeInteger(retryAfterSeconds) || retryAfterSeconds < 0)) {
|
|
94660
|
+
return void 0;
|
|
94661
|
+
}
|
|
94702
94662
|
const dependency = details["dependency"];
|
|
94703
94663
|
if (dependency !== void 0 && dependency !== "policy" && dependency !== "limiter") return void 0;
|
|
94664
|
+
if (!isCliQuotaCombinationValid(code, limitKind, quotaClass, scope, dependency)) return void 0;
|
|
94704
94665
|
return {
|
|
94705
|
-
limitKind
|
|
94706
|
-
quotaClass
|
|
94666
|
+
limitKind,
|
|
94667
|
+
quotaClass,
|
|
94707
94668
|
requestId: details["requestId"],
|
|
94708
94669
|
...scope === void 0 ? {} : { scope },
|
|
94709
|
-
...resetAt === void 0 ? {} : { resetAt },
|
|
94670
|
+
...resetAt === void 0 || limitKind === "concurrent" ? {} : { resetAt },
|
|
94671
|
+
...retryAfterSeconds === void 0 || limitKind === "concurrent" ? {} : { retryAfterSeconds },
|
|
94710
94672
|
...dependency === void 0 ? {} : { dependency }
|
|
94711
94673
|
};
|
|
94712
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
|
+
}
|
|
94713
94694
|
function parseRetryAfterSeconds(value) {
|
|
94714
94695
|
if (!value || !/^\d+$/.test(value)) return void 0;
|
|
94715
94696
|
const parsed = Number(value);
|
|
@@ -94968,7 +94949,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
94968
94949
|
});
|
|
94969
94950
|
const baseUrl = () => loadConfiguredApiBaseUrl();
|
|
94970
94951
|
const chatBaseUrl = () => loadConfiguredChatBaseUrl();
|
|
94971
|
-
const
|
|
94952
|
+
const requireReleaseEnabledOperation = (operationId) => {
|
|
94972
94953
|
if (buildEnv !== "prod") return _void;
|
|
94973
94954
|
if (!releaseEnabledCommandOperationIds.has(operationId)) {
|
|
94974
94955
|
return fail$3(createApiError({
|
|
@@ -94977,24 +94958,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
94977
94958
|
code: "CLI_OPERATION_NOT_ENABLED"
|
|
94978
94959
|
}));
|
|
94979
94960
|
}
|
|
94980
|
-
return
|
|
94981
|
-
const response = yield* makeRequest(
|
|
94982
|
-
baseUrl,
|
|
94983
|
-
"/api/cli/v1/capabilities",
|
|
94984
|
-
token
|
|
94985
|
-
);
|
|
94986
|
-
yield* try_({
|
|
94987
|
-
try: () => {
|
|
94988
|
-
const enabledOperations = parseEnabledServerOperations(response);
|
|
94989
|
-
requireEnabledServerOperation(enabledOperations, operationId);
|
|
94990
|
-
},
|
|
94991
|
-
catch: (error) => createApiError({
|
|
94992
|
-
message: error instanceof Error ? error.message : "CLI server capability validation failed",
|
|
94993
|
-
statusCode: error instanceof ServerCapabilityError && error.code === "CLI_OPERATION_NOT_ENABLED" ? 404 : 503,
|
|
94994
|
-
code: error instanceof ServerCapabilityError ? error.code : "CLI_CAPABILITIES_INCOMPATIBLE"
|
|
94995
|
-
})
|
|
94996
|
-
});
|
|
94997
|
-
});
|
|
94961
|
+
return _void;
|
|
94998
94962
|
};
|
|
94999
94963
|
const subscribeAgentChatStream = (orgSlug, conversationId, token) => gen(function* () {
|
|
95000
94964
|
const resolvedChatBaseUrl = yield* requireChatBaseUrlEffect();
|
|
@@ -95062,12 +95026,12 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95062
95026
|
return {
|
|
95063
95027
|
listOrganizations: () => gen(function* () {
|
|
95064
95028
|
const token = yield* getAccessToken();
|
|
95065
|
-
yield*
|
|
95029
|
+
yield* requireReleaseEnabledOperation("listCliOrganizations");
|
|
95066
95030
|
return yield* makeRequest(baseUrl, "/api/cli/v1/organizations", token);
|
|
95067
95031
|
}),
|
|
95068
95032
|
getOrganization: (slug) => gen(function* () {
|
|
95069
95033
|
const token = yield* getAccessToken();
|
|
95070
|
-
yield*
|
|
95034
|
+
yield* requireReleaseEnabledOperation("listCliOrganizations");
|
|
95071
95035
|
const orgs = yield* makeRequest(baseUrl, "/api/cli/v1/organizations", token);
|
|
95072
95036
|
const org = orgs.find((o) => o.slug === slug);
|
|
95073
95037
|
if (!org) {
|
|
@@ -95307,7 +95271,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95307
95271
|
// Phase 2: Agent management
|
|
95308
95272
|
listInstalledAgents: (orgSlug) => gen(function* () {
|
|
95309
95273
|
const token = yield* getAccessToken();
|
|
95310
|
-
yield*
|
|
95274
|
+
yield* requireReleaseEnabledOperation("listCliAgents");
|
|
95311
95275
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents`;
|
|
95312
95276
|
const raw = yield* makeRequest(baseUrl, path, token);
|
|
95313
95277
|
return {
|
|
@@ -95317,7 +95281,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95317
95281
|
}),
|
|
95318
95282
|
getInstalledAgent: (orgSlug, agentId) => gen(function* () {
|
|
95319
95283
|
const token = yield* getAccessToken();
|
|
95320
|
-
yield*
|
|
95284
|
+
yield* requireReleaseEnabledOperation("getCliAgent");
|
|
95321
95285
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}`;
|
|
95322
95286
|
const raw = yield* makeRequest(baseUrl, path, token);
|
|
95323
95287
|
return {
|
|
@@ -95330,7 +95294,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95330
95294
|
}),
|
|
95331
95295
|
updateInstalledAgentStatus: (orgSlug, agentId, status) => gen(function* () {
|
|
95332
95296
|
const token = yield* getAccessToken();
|
|
95333
|
-
yield*
|
|
95297
|
+
yield* requireReleaseEnabledOperation("updateCliAgentStatus");
|
|
95334
95298
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}/status`;
|
|
95335
95299
|
return yield* makeRequest(baseUrl, path, token, {
|
|
95336
95300
|
method: "PATCH",
|
|
@@ -95410,7 +95374,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95410
95374
|
// Phase 4: Monitoring
|
|
95411
95375
|
listOrgMembers: (orgSlug) => gen(function* () {
|
|
95412
95376
|
const token = yield* getAccessToken();
|
|
95413
|
-
yield*
|
|
95377
|
+
yield* requireReleaseEnabledOperation("listCliOrganizationMembers");
|
|
95414
95378
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/members`;
|
|
95415
95379
|
const raw = yield* makeRequest(baseUrl, path, token);
|
|
95416
95380
|
return {
|
|
@@ -95426,7 +95390,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95426
95390
|
listModels: (orgSlug) => gen(function* () {
|
|
95427
95391
|
yield* requireChatBaseUrlEffect();
|
|
95428
95392
|
const token = yield* getAccessToken();
|
|
95429
|
-
yield*
|
|
95393
|
+
yield* requireReleaseEnabledOperation("listCliModels");
|
|
95430
95394
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/models`;
|
|
95431
95395
|
const response = yield* makeRequest(chatBaseUrl, path, token);
|
|
95432
95396
|
return response.models.map((id) => ({
|
|
@@ -95437,14 +95401,14 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95437
95401
|
listModelExecModels: (orgSlug) => gen(function* () {
|
|
95438
95402
|
yield* requireChatBaseUrlEffect();
|
|
95439
95403
|
const token = yield* getAccessToken();
|
|
95440
|
-
yield*
|
|
95404
|
+
yield* requireReleaseEnabledOperation("listCliModelExecModels");
|
|
95441
95405
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/model-exec/models`;
|
|
95442
95406
|
return yield* makeRequest(chatBaseUrl, path, token);
|
|
95443
95407
|
}),
|
|
95444
95408
|
executeModelExecChat: (orgSlug, body) => gen(function* () {
|
|
95445
95409
|
yield* requireChatBaseUrlEffect();
|
|
95446
95410
|
const token = yield* getAccessToken();
|
|
95447
|
-
yield*
|
|
95411
|
+
yield* requireReleaseEnabledOperation("createCliModelChatExecution");
|
|
95448
95412
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/model-exec/chat`;
|
|
95449
95413
|
return yield* makeRequest(chatBaseUrl, path, token, {
|
|
95450
95414
|
method: "POST",
|
|
@@ -95586,7 +95550,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95586
95550
|
// Phase 6: Auth enhancements
|
|
95587
95551
|
getMe: () => gen(function* () {
|
|
95588
95552
|
const token = yield* getAccessToken();
|
|
95589
|
-
yield*
|
|
95553
|
+
yield* requireReleaseEnabledOperation("getCliMe");
|
|
95590
95554
|
return yield* makeRequest(baseUrl, "/api/cli/v1/me", token);
|
|
95591
95555
|
}),
|
|
95592
95556
|
refreshToken: () => refreshAccessToken({ force: true }),
|
|
@@ -95624,7 +95588,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95624
95588
|
// Phase 8: Agent admin CRUD
|
|
95625
95589
|
createInstalledAgent: (orgSlug, body) => gen(function* () {
|
|
95626
95590
|
const token = yield* getAccessToken();
|
|
95627
|
-
yield*
|
|
95591
|
+
yield* requireReleaseEnabledOperation("createCliAgent");
|
|
95628
95592
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents`;
|
|
95629
95593
|
return yield* makeRequest(baseUrl, path, token, {
|
|
95630
95594
|
method: "POST",
|
|
@@ -95633,7 +95597,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95633
95597
|
}),
|
|
95634
95598
|
updateInstalledAgent: (orgSlug, agentId, body) => gen(function* () {
|
|
95635
95599
|
const token = yield* getAccessToken();
|
|
95636
|
-
yield*
|
|
95600
|
+
yield* requireReleaseEnabledOperation("updateCliAgent");
|
|
95637
95601
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}`;
|
|
95638
95602
|
return yield* makeRequest(baseUrl, path, token, {
|
|
95639
95603
|
method: "PATCH",
|
|
@@ -95642,7 +95606,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95642
95606
|
}),
|
|
95643
95607
|
deleteInstalledAgent: (orgSlug, agentId) => gen(function* () {
|
|
95644
95608
|
const token = yield* getAccessToken();
|
|
95645
|
-
yield*
|
|
95609
|
+
yield* requireReleaseEnabledOperation("deleteCliAgent");
|
|
95646
95610
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}`;
|
|
95647
95611
|
return yield* makeRequest(baseUrl, path, token, { method: "DELETE" });
|
|
95648
95612
|
}),
|
|
@@ -95669,7 +95633,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95669
95633
|
}),
|
|
95670
95634
|
getInstalledAgentShare: (orgSlug, agentId) => gen(function* () {
|
|
95671
95635
|
const token = yield* getAccessToken();
|
|
95672
|
-
yield*
|
|
95636
|
+
yield* requireReleaseEnabledOperation("getCliAgentShare");
|
|
95673
95637
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}/share`;
|
|
95674
95638
|
const raw = yield* makeRequest(baseUrl, path, token);
|
|
95675
95639
|
const sharedUserList = yield* try_({
|
|
@@ -95683,7 +95647,7 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95683
95647
|
}),
|
|
95684
95648
|
listAgentTemplates: (orgSlug) => gen(function* () {
|
|
95685
95649
|
const token = yield* getAccessToken();
|
|
95686
|
-
yield*
|
|
95650
|
+
yield* requireReleaseEnabledOperation("listCliAgentTemplates");
|
|
95687
95651
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/agents/templates`;
|
|
95688
95652
|
const templates = [];
|
|
95689
95653
|
let page = 1;
|
|
@@ -95780,13 +95744,13 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95780
95744
|
// Org capabilities & user settings
|
|
95781
95745
|
getOrgCapabilities: (orgSlug) => gen(function* () {
|
|
95782
95746
|
const token = yield* getAccessToken();
|
|
95783
|
-
yield*
|
|
95747
|
+
yield* requireReleaseEnabledOperation("getCliOrganizationCapabilities");
|
|
95784
95748
|
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/capabilities`;
|
|
95785
95749
|
return yield* makeRequest(baseUrl, path, token);
|
|
95786
95750
|
}),
|
|
95787
95751
|
getUserSettings: () => gen(function* () {
|
|
95788
95752
|
const token = yield* getAccessToken();
|
|
95789
|
-
yield*
|
|
95753
|
+
yield* requireReleaseEnabledOperation("getCliUserSettings");
|
|
95790
95754
|
return yield* makeRequest(baseUrl, "/api/cli/v1/me/settings", token);
|
|
95791
95755
|
}),
|
|
95792
95756
|
// Tunnel management
|
|
@@ -68,15 +68,18 @@
|
|
|
68
68
|
|
|
69
69
|
## 공통 CLI request quota 오류 계약
|
|
70
70
|
|
|
71
|
-
`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`이다.
|
|
72
72
|
|
|
73
73
|
| HTTP | code | CLI 처리 |
|
|
74
74
|
| --- | --- | --- |
|
|
75
75
|
| 429 | `CLI_QUOTA_EXCEEDED` | `limitKind=request_rate`, quota class, denying scope, request ID를 보존한다. 양수 refill로 계산 가능한 경우에만 `Retry-After`, `resetAt`을 보존한다. 자동 retry는 하지 않는다. |
|
|
76
76
|
| 503 | `CLI_QUOTA_POLICY_UNAVAILABLE` | Backend effective-policy auth/timeout/schema/freshness 실패. stale/default policy로 대체하거나 자동 retry하지 않는다. |
|
|
77
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`을 만들거나 전달하지 않는다. |
|
|
78
81
|
|
|
79
|
-
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/**`에 있다.
|
|
80
83
|
|
|
81
84
|
## Queue IDs for follow-up
|
|
82
85
|
|
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": {
|