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 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$3 = input => isRecordOrArray(input) && !Array.isArray(input);
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$3(input)) {
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.8".length > 0 ? "2026.9.8" : "0.0.0";
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$2(value) {
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$2(value)) {
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$2(value)) {
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$1(value) {
92906
+ function isNonEmptyString(value) {
92907
92907
  return typeof value === "string" && value.length > 0;
92908
92908
  }
92909
92909
  function hasOAuthClient(credentials) {
92910
- return isNonEmptyString$1(credentials?.clientId);
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$1(credentials.refreshToken) && (credentials.refreshExpiresAt === void 0 || credentials.refreshExpiresAt > now);
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$1(credentials.accessToken) || isAccessTokenExpired(credentials, options.accessExpiryBufferMs ?? 0, now);
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$1(value) {
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$1(value)) {
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 details = isCliQuotaErrorCode(errorData.code) ? parseCliQuotaErrorDetails(errorData.details) : void 0;
94674
- const retryAfterSeconds = details ? parseRetryAfterSeconds(response.headers.get("retry-after")) : void 0;
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: errorData.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 parseCliQuotaErrorDetails(value) {
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
- if (details["limitKind"] !== "request_rate") return void 0;
94690
- if (typeof details["quotaClass"] !== "string" || !["bootstrap", "metadata", "text-execution", "control-read"].includes(details["quotaClass"])) {
94691
- return void 0;
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: "request_rate",
94706
- quotaClass: details["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 requireServerOperation = (operationId, token) => {
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 gen(function* () {
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* requireServerOperation("listCliOrganizations", token);
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* requireServerOperation("listCliOrganizations", token);
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* requireServerOperation("listCliAgents", token);
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* requireServerOperation("getCliAgent", token);
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* requireServerOperation("updateCliAgentStatus", token);
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* requireServerOperation("listCliOrganizationMembers", token);
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* requireServerOperation("listCliModels", token);
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* requireServerOperation("listCliModelExecModels", token);
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* requireServerOperation("createCliModelChatExecution", token);
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* requireServerOperation("getCliMe", token);
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* requireServerOperation("createCliAgent", token);
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* requireServerOperation("updateCliAgent", token);
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* requireServerOperation("deleteCliAgent", token);
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* requireServerOperation("getCliAgentShare", token);
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* requireServerOperation("listCliAgentTemplates", token);
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* requireServerOperation("getCliOrganizationCapabilities", token);
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* requireServerOperation("getCliUserSettings", token);
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`는 위 세 code에서 allowlist된 quota detail만 보존하며 서버가 추가로 보낸 조직/사용자 ID, raw policy, Redis key는 노출하지 않는다. 회귀 테스트는 `src/core/api.test.ts`와 Gateway `test/cli/quota/**`에 있다.
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.8",
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": "fc535c50b1c26702237a8dbfd683f04ddaec6b84c369c308b9714d1e65c5fc69",
26
- "wrapperHash": "69f4f9d9e2ed5283318f3b770870f094ae315b9cc579ad426203224c66624461",
25
+ "contentHash": "95bfb896d5e0e21910685b39eff86f3d35ee5c1b0ef28854912f78fdbc7bee58",
26
+ "wrapperHash": "a4ef2565f44cb9eb4a3706246f59427bf40a5275dc7bea030fb30024be6f5ab8",
27
27
  "nativeHash": "006b08c3e391f4571d9b7c0f12d684fe2448106259e7e0581b10f9be362452e9"
28
28
  },
29
29
  "optionalDependencies": {