aipctl 2026.9.3 → 2026.9.5

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$2 = input => isRecordOrArray(input) && !Array.isArray(input);
781
+ const isRecord$3 = 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$2(input)) {
25161
+ if (!isRecord$3(input)) {
25162
25162
  return left(new Type(ast, input));
25163
25163
  }
25164
25164
  const allErrors = options?.errors === "all";
@@ -89666,11 +89666,11 @@ const runMain = runMain$1;
89666
89666
  const BUILD_ENVS = ["local", "dev", "qa", "stage", "prod", "test"];
89667
89667
  const isBuildEnv = (value) => BUILD_ENVS.includes(value);
89668
89668
 
89669
- const injectedBuildEnv = "prod".length > 0 ? "prod" : "local";
89669
+ 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.3".length > 0 ? "2026.9.3" : "0.0.0";
89673
+ const VERSION = "2026.9.5".length > 0 ? "2026.9.5" : "0.0.0";
89674
89674
  const BUILD_ENV = injectedBuildEnv;
89675
89675
  const INCLUDE_NATIVE_LOGS = BUILD_ENV !== "prod";
89676
89676
 
@@ -89803,6 +89803,812 @@ const normalizeAipArgs = (args) => {
89803
89803
  ];
89804
89804
  };
89805
89805
 
89806
+ const implementedCommandOperationIds = /* @__PURE__ */ new Set([
89807
+ "getCliMe",
89808
+ "getCliUserSettings",
89809
+ "listCliOrganizations",
89810
+ "getCliOrganizationCapabilities",
89811
+ "listCliOrganizationMembers",
89812
+ "listCliModelExecModels",
89813
+ "createCliModelChatExecution"
89814
+ ]);
89815
+ const releaseEnabledCommandOperationIds = /* @__PURE__ */ new Set([
89816
+ "getCliMe",
89817
+ "getCliUserSettings",
89818
+ "listCliOrganizations",
89819
+ "getCliOrganizationCapabilities",
89820
+ "listCliOrganizationMembers",
89821
+ "listCliModelExecModels"
89822
+ ]);
89823
+ const direct = (commands, operation) => commands.map((command) => ({
89824
+ command,
89825
+ tier: "GA_DIRECT",
89826
+ availability: !implementedCommandOperationIds.has(operation.operationId ?? "") ? "PLANNED" : releaseEnabledCommandOperationIds.has(operation.operationId ?? "") ? "IMPLEMENTED" : "GATED",
89827
+ ...operation
89828
+ }));
89829
+ const candidate = (commands, owner, authBoundary, requiredGates) => commands.map((command) => ({
89830
+ command,
89831
+ tier: "GA_CANDIDATE",
89832
+ owner,
89833
+ authBoundary,
89834
+ quotaClass: "endpoint-guard",
89835
+ availability: "GATED",
89836
+ capability: `cli.${command.replaceAll(" ", ".")}`,
89837
+ requiredGates
89838
+ }));
89839
+ const fixedBoundary = (commands, tier, owner, authBoundary) => commands.map((command) => ({
89840
+ command,
89841
+ tier,
89842
+ owner,
89843
+ authBoundary,
89844
+ quotaClass: "none",
89845
+ availability: tier === "INTERNAL_HIDDEN" ? "HIDDEN" : "AVAILABLE"
89846
+ }));
89847
+ const orgPath = "/api/cli/v1/organizations/{organizationSlug}";
89848
+ const commandManifest = [
89849
+ ...direct(["auth whoami"], {
89850
+ owner: "backend",
89851
+ authBoundary: "user-oauth",
89852
+ quotaClass: "bootstrap",
89853
+ endpoint: { method: "GET", path: "/api/cli/v1/me" },
89854
+ operationId: "getCliMe",
89855
+ canonicalOperation: "cli.identity.me.read",
89856
+ capability: "cli.identity.me"
89857
+ }),
89858
+ ...direct(["org list", "org use", "org select"], {
89859
+ owner: "backend",
89860
+ authBoundary: "user-oauth",
89861
+ quotaClass: "bootstrap",
89862
+ endpoint: { method: "GET", path: "/api/cli/v1/organizations" },
89863
+ operationId: "listCliOrganizations",
89864
+ canonicalOperation: "cli.organization.list",
89865
+ capability: "cli.organization.discovery"
89866
+ }),
89867
+ ...direct(["org capabilities"], {
89868
+ owner: "backend",
89869
+ authBoundary: "organization-oauth",
89870
+ quotaClass: "metadata",
89871
+ endpoint: { method: "GET", path: `${orgPath}/capabilities` },
89872
+ operationId: "getCliOrganizationCapabilities",
89873
+ canonicalOperation: "cli.organization.capabilities.read",
89874
+ capability: "cli.organization.capabilities"
89875
+ }),
89876
+ ...direct(["org settings"], {
89877
+ owner: "backend",
89878
+ authBoundary: "user-oauth",
89879
+ quotaClass: "bootstrap",
89880
+ endpoint: { method: "GET", path: "/api/cli/v1/me/settings" },
89881
+ operationId: "getCliUserSettings",
89882
+ canonicalOperation: "cli.user.settings.read",
89883
+ capability: "cli.user.settings"
89884
+ }),
89885
+ ...direct(["org members"], {
89886
+ owner: "backend",
89887
+ authBoundary: "organization-oauth",
89888
+ quotaClass: "metadata",
89889
+ endpoint: { method: "GET", path: `${orgPath}/members` },
89890
+ operationId: "listCliOrganizationMembers",
89891
+ canonicalOperation: "cli.organization.members.list",
89892
+ capability: "cli.organization.members.read"
89893
+ }),
89894
+ ...direct(["org exit"], {
89895
+ owner: "backend",
89896
+ authBoundary: "organization-oauth",
89897
+ quotaClass: "metadata",
89898
+ endpoint: { method: "DELETE", path: `${orgPath}/membership` },
89899
+ operationId: "deleteCliOrganizationMembership",
89900
+ canonicalOperation: "cli.organization.membership.exit",
89901
+ capability: "cli.organization.exit"
89902
+ }),
89903
+ ...direct(["admin org invite"], {
89904
+ owner: "backend",
89905
+ authBoundary: "organization-oauth",
89906
+ quotaClass: "metadata",
89907
+ endpoint: { method: "POST", path: `${orgPath}/members/invitations` },
89908
+ operationId: "createCliOrganizationMemberInvitations",
89909
+ canonicalOperation: "cli.organization.members.invite",
89910
+ capability: "cli.organization.members.write"
89911
+ }),
89912
+ ...direct(["admin org remove-member"], {
89913
+ owner: "backend",
89914
+ authBoundary: "organization-oauth",
89915
+ quotaClass: "metadata",
89916
+ endpoint: { method: "DELETE", path: `${orgPath}/members` },
89917
+ operationId: "deleteCliOrganizationMembers",
89918
+ canonicalOperation: "cli.organization.members.remove",
89919
+ capability: "cli.organization.members.write"
89920
+ }),
89921
+ ...direct(["admin org update-member-role"], {
89922
+ owner: "backend",
89923
+ authBoundary: "organization-oauth",
89924
+ quotaClass: "metadata",
89925
+ endpoint: { method: "PUT", path: `${orgPath}/members/role` },
89926
+ operationId: "updateCliOrganizationMemberRoles",
89927
+ canonicalOperation: "cli.organization.members.role.update",
89928
+ capability: "cli.organization.members.write"
89929
+ }),
89930
+ ...direct(["model list"], {
89931
+ owner: "chat",
89932
+ authBoundary: "organization-oauth",
89933
+ quotaClass: "metadata",
89934
+ endpoint: { method: "GET", path: `${orgPath}/models` },
89935
+ operationId: "listCliModels",
89936
+ canonicalOperation: "cli.model.catalog.read",
89937
+ capability: "cli.model.catalog"
89938
+ }),
89939
+ ...direct(["model-exec models", "model-exec get", "model-exec sample"], {
89940
+ owner: "chat",
89941
+ authBoundary: "organization-oauth",
89942
+ quotaClass: "metadata",
89943
+ endpoint: { method: "GET", path: `${orgPath}/model-exec/models` },
89944
+ operationId: "listCliModelExecModels",
89945
+ canonicalOperation: "cli.model.catalog.read",
89946
+ capability: "cli.model.catalog"
89947
+ }),
89948
+ ...direct(["model-exec chat"], {
89949
+ owner: "chat",
89950
+ authBoundary: "organization-oauth",
89951
+ quotaClass: "text-execution",
89952
+ endpoint: { method: "POST", path: `${orgPath}/model-exec/chat` },
89953
+ operationId: "createCliModelChatExecution",
89954
+ canonicalOperation: "cli.model.text.execute",
89955
+ capability: "cli.model.text.execute"
89956
+ }),
89957
+ ...direct(["agent list"], {
89958
+ owner: "backend",
89959
+ authBoundary: "organization-oauth",
89960
+ quotaClass: "metadata",
89961
+ endpoint: { method: "GET", path: `${orgPath}/agents` },
89962
+ operationId: "listCliAgents",
89963
+ canonicalOperation: "cli.agent.list",
89964
+ capability: "cli.agent.read"
89965
+ }),
89966
+ ...direct(["agent get"], {
89967
+ owner: "backend",
89968
+ authBoundary: "organization-oauth",
89969
+ quotaClass: "metadata",
89970
+ endpoint: { method: "GET", path: `${orgPath}/agents/{installedAgentId}` },
89971
+ operationId: "getCliAgent",
89972
+ canonicalOperation: "cli.agent.get",
89973
+ capability: "cli.agent.read"
89974
+ }),
89975
+ ...direct(["agent enable", "agent disable"], {
89976
+ owner: "backend",
89977
+ authBoundary: "organization-oauth",
89978
+ quotaClass: "metadata",
89979
+ endpoint: { method: "PATCH", path: `${orgPath}/agents/{installedAgentId}/status` },
89980
+ operationId: "updateCliAgentStatus",
89981
+ canonicalOperation: "cli.agent.status.update",
89982
+ capability: "cli.agent.write"
89983
+ }),
89984
+ ...direct(["admin agent templates"], {
89985
+ owner: "backend",
89986
+ authBoundary: "organization-oauth",
89987
+ quotaClass: "metadata",
89988
+ endpoint: { method: "GET", path: `${orgPath}/agents/templates` },
89989
+ operationId: "listCliAgentTemplates",
89990
+ canonicalOperation: "cli.agent.templates.list",
89991
+ capability: "cli.agent.read"
89992
+ }),
89993
+ ...direct(["admin agent create"], {
89994
+ owner: "backend",
89995
+ authBoundary: "organization-oauth",
89996
+ quotaClass: "metadata",
89997
+ endpoint: { method: "POST", path: `${orgPath}/agents` },
89998
+ operationId: "createCliAgent",
89999
+ canonicalOperation: "cli.agent.create",
90000
+ capability: "cli.agent.write"
90001
+ }),
90002
+ ...direct(["admin agent update"], {
90003
+ owner: "backend",
90004
+ authBoundary: "organization-oauth",
90005
+ quotaClass: "metadata",
90006
+ endpoint: { method: "PATCH", path: `${orgPath}/agents/{installedAgentId}` },
90007
+ operationId: "updateCliAgent",
90008
+ canonicalOperation: "cli.agent.update",
90009
+ capability: "cli.agent.write"
90010
+ }),
90011
+ ...direct(["admin agent delete"], {
90012
+ owner: "backend",
90013
+ authBoundary: "organization-oauth",
90014
+ quotaClass: "metadata",
90015
+ endpoint: { method: "DELETE", path: `${orgPath}/agents/{installedAgentId}` },
90016
+ operationId: "deleteCliAgent",
90017
+ canonicalOperation: "cli.agent.delete",
90018
+ capability: "cli.agent.write"
90019
+ }),
90020
+ ...direct(["admin agent share"], {
90021
+ owner: "backend",
90022
+ authBoundary: "organization-oauth",
90023
+ quotaClass: "metadata",
90024
+ endpoint: { method: "GET", path: `${orgPath}/agents/{installedAgentId}/share` },
90025
+ operationId: "getCliAgentShare",
90026
+ canonicalOperation: "cli.agent.share.read",
90027
+ capability: "cli.agent.read"
90028
+ }),
90029
+ ...direct(["skill list"], {
90030
+ owner: "backend",
90031
+ authBoundary: "organization-oauth",
90032
+ quotaClass: "metadata",
90033
+ endpoint: { method: "GET", path: `${orgPath}/skills` },
90034
+ operationId: "listCliSkills",
90035
+ canonicalOperation: "cli.skill.list",
90036
+ capability: "cli.skill.read"
90037
+ }),
90038
+ ...direct(["skill get"], {
90039
+ owner: "backend",
90040
+ authBoundary: "organization-oauth",
90041
+ quotaClass: "metadata",
90042
+ endpoint: { method: "GET", path: `${orgPath}/skills/{skillId}` },
90043
+ operationId: "getCliSkill",
90044
+ canonicalOperation: "cli.skill.get",
90045
+ capability: "cli.skill.read"
90046
+ }),
90047
+ ...direct(["skill delete"], {
90048
+ owner: "backend",
90049
+ authBoundary: "organization-oauth",
90050
+ quotaClass: "metadata",
90051
+ endpoint: { method: "DELETE", path: `${orgPath}/skills/{skillId}` },
90052
+ operationId: "deleteCliSkill",
90053
+ canonicalOperation: "cli.skill.delete",
90054
+ capability: "cli.skill.write"
90055
+ }),
90056
+ ...direct(["skill library"], {
90057
+ owner: "backend",
90058
+ authBoundary: "organization-oauth",
90059
+ quotaClass: "metadata",
90060
+ endpoint: { method: "GET", path: `${orgPath}/skills/library` },
90061
+ operationId: "listCliSkillLibrary",
90062
+ canonicalOperation: "cli.skill.library.list",
90063
+ capability: "cli.skill.read"
90064
+ }),
90065
+ ...direct(["skill clone"], {
90066
+ owner: "backend",
90067
+ authBoundary: "organization-oauth",
90068
+ quotaClass: "metadata",
90069
+ endpoint: { method: "POST", path: `${orgPath}/skills/library/clone` },
90070
+ operationId: "createCliSkillClones",
90071
+ canonicalOperation: "cli.skill.library.clone",
90072
+ capability: "cli.skill.write"
90073
+ }),
90074
+ ...direct(["skill built-in"], {
90075
+ owner: "backend",
90076
+ authBoundary: "organization-oauth",
90077
+ quotaClass: "metadata",
90078
+ endpoint: { method: "GET", path: `${orgPath}/skills/built-in` },
90079
+ operationId: "listCliBuiltInSkills",
90080
+ canonicalOperation: "cli.skill.built-in.list",
90081
+ capability: "cli.skill.read"
90082
+ }),
90083
+ ...direct(["skill clone-built-in"], {
90084
+ owner: "backend",
90085
+ authBoundary: "organization-oauth",
90086
+ quotaClass: "metadata",
90087
+ endpoint: { method: "POST", path: `${orgPath}/skills/built-in/clone` },
90088
+ operationId: "createCliBuiltInSkillClones",
90089
+ canonicalOperation: "cli.skill.built-in.clone",
90090
+ capability: "cli.skill.write"
90091
+ }),
90092
+ ...direct(["admin skill list"], {
90093
+ owner: "backend",
90094
+ authBoundary: "organization-oauth",
90095
+ quotaClass: "metadata",
90096
+ endpoint: { method: "GET", path: `${orgPath}/admin/skills` },
90097
+ operationId: "listCliAdminSkills",
90098
+ canonicalOperation: "cli.admin.skill.list",
90099
+ capability: "cli.admin.skill.read"
90100
+ }),
90101
+ ...direct(["admin skill get"], {
90102
+ owner: "backend",
90103
+ authBoundary: "organization-oauth",
90104
+ quotaClass: "metadata",
90105
+ endpoint: { method: "GET", path: `${orgPath}/admin/skills/{skillId}` },
90106
+ operationId: "getCliAdminSkill",
90107
+ canonicalOperation: "cli.admin.skill.get",
90108
+ capability: "cli.admin.skill.read"
90109
+ }),
90110
+ ...direct(["admin skill delete"], {
90111
+ owner: "backend",
90112
+ authBoundary: "organization-oauth",
90113
+ quotaClass: "metadata",
90114
+ endpoint: { method: "DELETE", path: `${orgPath}/admin/skills/{skillId}` },
90115
+ operationId: "deleteCliAdminSkill",
90116
+ canonicalOperation: "cli.admin.skill.delete",
90117
+ capability: "cli.admin.skill.write"
90118
+ }),
90119
+ ...direct(["admin skill publish", "admin skill unpublish"], {
90120
+ owner: "backend",
90121
+ authBoundary: "organization-oauth",
90122
+ quotaClass: "metadata",
90123
+ endpoint: { method: "PATCH", path: `${orgPath}/admin/skills/{skillId}` },
90124
+ operationId: "updateCliAdminSkill",
90125
+ canonicalOperation: "cli.admin.skill.update",
90126
+ capability: "cli.admin.skill.write"
90127
+ }),
90128
+ ...direct(["admin skill built-in"], {
90129
+ owner: "backend",
90130
+ authBoundary: "organization-oauth",
90131
+ quotaClass: "metadata",
90132
+ endpoint: { method: "GET", path: `${orgPath}/admin/skills/built-in` },
90133
+ operationId: "listCliAdminBuiltInSkills",
90134
+ canonicalOperation: "cli.admin.skill.built-in.list",
90135
+ capability: "cli.admin.skill.read"
90136
+ }),
90137
+ ...direct(["admin skill clone-built-in"], {
90138
+ owner: "backend",
90139
+ authBoundary: "organization-oauth",
90140
+ quotaClass: "metadata",
90141
+ endpoint: { method: "POST", path: `${orgPath}/admin/skills/built-in/clone` },
90142
+ operationId: "createCliAdminBuiltInSkillClones",
90143
+ canonicalOperation: "cli.admin.skill.built-in.clone",
90144
+ capability: "cli.admin.skill.write"
90145
+ }),
90146
+ ...direct(["drive list"], {
90147
+ owner: "backend",
90148
+ authBoundary: "organization-oauth",
90149
+ quotaClass: "metadata",
90150
+ endpoint: { method: "GET", path: `${orgPath}/drive/entries` },
90151
+ operationId: "listCliDriveEntries",
90152
+ canonicalOperation: "cli.drive.entries.list",
90153
+ capability: "cli.drive.read"
90154
+ }),
90155
+ ...direct(["drive usage"], {
90156
+ owner: "backend",
90157
+ authBoundary: "organization-oauth",
90158
+ quotaClass: "metadata",
90159
+ endpoint: { method: "GET", path: `${orgPath}/drive/usage` },
90160
+ operationId: "getCliDriveUsage",
90161
+ canonicalOperation: "cli.drive.usage.read",
90162
+ capability: "cli.drive.read"
90163
+ }),
90164
+ ...direct(["drive mkdir"], {
90165
+ owner: "backend",
90166
+ authBoundary: "organization-oauth",
90167
+ quotaClass: "metadata",
90168
+ endpoint: { method: "POST", path: `${orgPath}/drive/folders` },
90169
+ operationId: "createCliDriveFolder",
90170
+ canonicalOperation: "cli.drive.folder.create",
90171
+ capability: "cli.drive.write"
90172
+ }),
90173
+ ...direct(["drive rename"], {
90174
+ owner: "backend",
90175
+ authBoundary: "organization-oauth",
90176
+ quotaClass: "metadata",
90177
+ endpoint: { method: "PATCH", path: `${orgPath}/drive/entries/{entryId}` },
90178
+ operationId: "updateCliDriveEntryName",
90179
+ canonicalOperation: "cli.drive.entry.rename",
90180
+ capability: "cli.drive.write"
90181
+ }),
90182
+ ...direct(["drive delete"], {
90183
+ owner: "backend",
90184
+ authBoundary: "organization-oauth",
90185
+ quotaClass: "metadata",
90186
+ endpoint: { method: "POST", path: `${orgPath}/drive/entries/delete` },
90187
+ operationId: "deleteCliDriveEntries",
90188
+ canonicalOperation: "cli.drive.entries.delete",
90189
+ capability: "cli.drive.write"
90190
+ }),
90191
+ ...direct(["chat list"], {
90192
+ owner: "chat",
90193
+ authBoundary: "organization-oauth",
90194
+ quotaClass: "metadata",
90195
+ endpoint: { method: "GET", path: `${orgPath}/chats` },
90196
+ operationId: "listCliChats",
90197
+ canonicalOperation: "cli.chat.list",
90198
+ capability: "cli.chat.read"
90199
+ }),
90200
+ ...direct(["chat get"], {
90201
+ owner: "chat",
90202
+ authBoundary: "organization-oauth",
90203
+ quotaClass: "metadata",
90204
+ endpoint: { method: "GET", path: `${orgPath}/chats/{conversationId}` },
90205
+ operationId: "getCliChat",
90206
+ canonicalOperation: "cli.chat.get",
90207
+ capability: "cli.chat.read"
90208
+ }),
90209
+ ...direct(["chat messages"], {
90210
+ owner: "chat",
90211
+ authBoundary: "organization-oauth",
90212
+ quotaClass: "metadata",
90213
+ endpoint: { method: "GET", path: `${orgPath}/chats/{conversationId}/messages` },
90214
+ operationId: "listCliChatMessages",
90215
+ canonicalOperation: "cli.chat.messages.list",
90216
+ capability: "cli.chat.read"
90217
+ }),
90218
+ ...direct(["integration list"], {
90219
+ owner: "backend",
90220
+ authBoundary: "organization-oauth",
90221
+ quotaClass: "metadata",
90222
+ endpoint: { method: "GET", path: `${orgPath}/integrations` },
90223
+ operationId: "listCliIntegrations",
90224
+ canonicalOperation: "cli.integration.list",
90225
+ capability: "cli.integration.read"
90226
+ }),
90227
+ ...direct(["admin integration available"], {
90228
+ owner: "backend",
90229
+ authBoundary: "organization-oauth",
90230
+ quotaClass: "metadata",
90231
+ endpoint: { method: "GET", path: `${orgPath}/admin/integrations/available` },
90232
+ operationId: "listCliAvailableIntegrations",
90233
+ canonicalOperation: "cli.admin.integration.available.list",
90234
+ capability: "cli.admin.integration.read"
90235
+ }),
90236
+ ...direct(["admin integration get"], {
90237
+ owner: "backend",
90238
+ authBoundary: "organization-oauth",
90239
+ quotaClass: "metadata",
90240
+ endpoint: { method: "GET", path: `${orgPath}/admin/integrations/{integrationId}` },
90241
+ operationId: "getCliAdminIntegration",
90242
+ canonicalOperation: "cli.admin.integration.get",
90243
+ capability: "cli.admin.integration.read"
90244
+ }),
90245
+ ...direct(["admin integration tools"], {
90246
+ owner: "backend",
90247
+ authBoundary: "organization-oauth",
90248
+ quotaClass: "metadata",
90249
+ endpoint: { method: "GET", path: `${orgPath}/admin/integrations/{integrationId}/tools` },
90250
+ operationId: "listCliIntegrationTools",
90251
+ canonicalOperation: "cli.admin.integration.tools.list",
90252
+ capability: "cli.admin.integration.read"
90253
+ }),
90254
+ ...direct(["automation list"], {
90255
+ owner: "backend",
90256
+ authBoundary: "organization-oauth",
90257
+ quotaClass: "metadata",
90258
+ endpoint: { method: "GET", path: `${orgPath}/automations` },
90259
+ operationId: "listCliAutomations",
90260
+ canonicalOperation: "cli.automation.list",
90261
+ capability: "cli.automation.read"
90262
+ }),
90263
+ ...direct(["automation get"], {
90264
+ owner: "backend",
90265
+ authBoundary: "organization-oauth",
90266
+ quotaClass: "metadata",
90267
+ endpoint: { method: "GET", path: `${orgPath}/automations/{automationId}` },
90268
+ operationId: "getCliAutomation",
90269
+ canonicalOperation: "cli.automation.get",
90270
+ capability: "cli.automation.read"
90271
+ }),
90272
+ ...direct(["automation triggers"], {
90273
+ owner: "backend",
90274
+ authBoundary: "organization-oauth",
90275
+ quotaClass: "metadata",
90276
+ endpoint: { method: "GET", path: `${orgPath}/automations/triggers` },
90277
+ operationId: "listCliAutomationTriggers",
90278
+ canonicalOperation: "cli.automation.triggers.list",
90279
+ capability: "cli.automation.read"
90280
+ }),
90281
+ ...direct(["automation history"], {
90282
+ owner: "backend",
90283
+ authBoundary: "organization-oauth",
90284
+ quotaClass: "metadata",
90285
+ endpoint: { method: "GET", path: `${orgPath}/automations/{automationId}/history` },
90286
+ operationId: "listCliAutomationHistory",
90287
+ canonicalOperation: "cli.automation.history.list",
90288
+ capability: "cli.automation.read"
90289
+ }),
90290
+ ...direct(["automation create"], {
90291
+ owner: "backend",
90292
+ authBoundary: "organization-oauth",
90293
+ quotaClass: "metadata",
90294
+ endpoint: { method: "POST", path: `${orgPath}/automations` },
90295
+ operationId: "createCliAutomation",
90296
+ canonicalOperation: "cli.automation.create",
90297
+ capability: "cli.automation.write"
90298
+ }),
90299
+ ...direct(["automation update"], {
90300
+ owner: "backend",
90301
+ authBoundary: "organization-oauth",
90302
+ quotaClass: "metadata",
90303
+ endpoint: { method: "PUT", path: `${orgPath}/automations/{automationId}` },
90304
+ operationId: "updateCliAutomation",
90305
+ canonicalOperation: "cli.automation.update",
90306
+ capability: "cli.automation.write"
90307
+ }),
90308
+ ...direct(["automation delete"], {
90309
+ owner: "backend",
90310
+ authBoundary: "organization-oauth",
90311
+ quotaClass: "metadata",
90312
+ endpoint: { method: "DELETE", path: `${orgPath}/automations/{automationId}` },
90313
+ operationId: "deleteCliAutomation",
90314
+ canonicalOperation: "cli.automation.delete",
90315
+ capability: "cli.automation.write"
90316
+ }),
90317
+ ...direct(["automation enable", "automation disable"], {
90318
+ owner: "backend",
90319
+ authBoundary: "organization-oauth",
90320
+ quotaClass: "metadata",
90321
+ endpoint: { method: "PATCH", path: `${orgPath}/automations/{automationId}/status` },
90322
+ operationId: "updateCliAutomationStatus",
90323
+ canonicalOperation: "cli.automation.status.update",
90324
+ capability: "cli.automation.write"
90325
+ }),
90326
+ ...direct(["admin usage credit"], {
90327
+ owner: "backend",
90328
+ authBoundary: "organization-oauth",
90329
+ quotaClass: "metadata",
90330
+ endpoint: { method: "GET", path: `${orgPath}/admin/usage/credit` },
90331
+ operationId: "getCliCreditUsage",
90332
+ canonicalOperation: "cli.admin.usage.credit.read",
90333
+ capability: "cli.admin.usage.read"
90334
+ }),
90335
+ ...direct(["admin usage top-users"], {
90336
+ owner: "backend",
90337
+ authBoundary: "organization-oauth",
90338
+ quotaClass: "metadata",
90339
+ endpoint: { method: "GET", path: `${orgPath}/admin/usage/top-users` },
90340
+ operationId: "listCliTopUsers",
90341
+ canonicalOperation: "cli.admin.usage.top-users.read",
90342
+ capability: "cli.admin.usage.read"
90343
+ }),
90344
+ ...direct(["admin usage daily-graph"], {
90345
+ owner: "backend",
90346
+ authBoundary: "organization-oauth",
90347
+ quotaClass: "metadata",
90348
+ endpoint: { method: "GET", path: `${orgPath}/admin/usage/daily-graph` },
90349
+ operationId: "getCliDailyUsageGraph",
90350
+ canonicalOperation: "cli.admin.usage.daily-graph.read",
90351
+ capability: "cli.admin.usage.read"
90352
+ }),
90353
+ ...direct(["admin usage daily-users"], {
90354
+ owner: "backend",
90355
+ authBoundary: "organization-oauth",
90356
+ quotaClass: "metadata",
90357
+ endpoint: { method: "GET", path: `${orgPath}/admin/usage/daily-users` },
90358
+ operationId: "listCliDailyUsers",
90359
+ canonicalOperation: "cli.admin.usage.daily-users.read",
90360
+ capability: "cli.admin.usage.read"
90361
+ }),
90362
+ ...direct(["admin usage mcp-top"], {
90363
+ owner: "backend",
90364
+ authBoundary: "organization-oauth",
90365
+ quotaClass: "metadata",
90366
+ endpoint: { method: "GET", path: `${orgPath}/admin/usage/mcp-top` },
90367
+ operationId: "listCliTopMcpTools",
90368
+ canonicalOperation: "cli.admin.usage.mcp-top.read",
90369
+ capability: "cli.admin.usage.read"
90370
+ }),
90371
+ ...direct(["admin audit list"], {
90372
+ owner: "backend",
90373
+ authBoundary: "organization-oauth",
90374
+ quotaClass: "metadata",
90375
+ endpoint: { method: "GET", path: `${orgPath}/admin/audit` },
90376
+ operationId: "listCliAuditLogs",
90377
+ canonicalOperation: "cli.admin.audit.list",
90378
+ capability: "cli.admin.audit.read"
90379
+ }),
90380
+ ...direct(["admin audit types"], {
90381
+ owner: "backend",
90382
+ authBoundary: "organization-oauth",
90383
+ quotaClass: "metadata",
90384
+ endpoint: { method: "GET", path: `${orgPath}/admin/audit/types` },
90385
+ operationId: "listCliAuditEventTypes",
90386
+ canonicalOperation: "cli.admin.audit.types.list",
90387
+ capability: "cli.admin.audit.read"
90388
+ }),
90389
+ ...direct(["admin preset list"], {
90390
+ owner: "backend",
90391
+ authBoundary: "organization-oauth",
90392
+ quotaClass: "metadata",
90393
+ endpoint: { method: "GET", path: `${orgPath}/admin/presets` },
90394
+ operationId: "listCliPresets",
90395
+ canonicalOperation: "cli.admin.preset.list",
90396
+ capability: "cli.admin.preset.read"
90397
+ }),
90398
+ ...direct(["admin preset get"], {
90399
+ owner: "backend",
90400
+ authBoundary: "organization-oauth",
90401
+ quotaClass: "metadata",
90402
+ endpoint: { method: "GET", path: `${orgPath}/admin/presets/{presetId}` },
90403
+ operationId: "getCliPreset",
90404
+ canonicalOperation: "cli.admin.preset.get",
90405
+ capability: "cli.admin.preset.read"
90406
+ }),
90407
+ ...direct(["admin preset create"], {
90408
+ owner: "backend",
90409
+ authBoundary: "organization-oauth",
90410
+ quotaClass: "metadata",
90411
+ endpoint: { method: "POST", path: `${orgPath}/admin/presets` },
90412
+ operationId: "createCliPreset",
90413
+ canonicalOperation: "cli.admin.preset.create",
90414
+ capability: "cli.admin.preset.write"
90415
+ }),
90416
+ ...direct(["admin preset update"], {
90417
+ owner: "backend",
90418
+ authBoundary: "organization-oauth",
90419
+ quotaClass: "metadata",
90420
+ endpoint: { method: "PUT", path: `${orgPath}/admin/presets/{presetId}` },
90421
+ operationId: "updateCliPreset",
90422
+ canonicalOperation: "cli.admin.preset.update",
90423
+ capability: "cli.admin.preset.write"
90424
+ }),
90425
+ ...direct(["admin preset rename"], {
90426
+ owner: "backend",
90427
+ authBoundary: "organization-oauth",
90428
+ quotaClass: "metadata",
90429
+ endpoint: { method: "PATCH", path: `${orgPath}/admin/presets/{presetId}` },
90430
+ operationId: "updateCliPresetName",
90431
+ canonicalOperation: "cli.admin.preset.rename",
90432
+ capability: "cli.admin.preset.write"
90433
+ }),
90434
+ ...direct(["admin preset delete"], {
90435
+ owner: "backend",
90436
+ authBoundary: "organization-oauth",
90437
+ quotaClass: "metadata",
90438
+ endpoint: { method: "DELETE", path: `${orgPath}/admin/presets/{presetId}` },
90439
+ operationId: "deleteCliPreset",
90440
+ canonicalOperation: "cli.admin.preset.delete",
90441
+ capability: "cli.admin.preset.write"
90442
+ }),
90443
+ ...direct(["admin preset set-default"], {
90444
+ owner: "backend",
90445
+ authBoundary: "organization-oauth",
90446
+ quotaClass: "metadata",
90447
+ endpoint: { method: "PUT", path: `${orgPath}/admin/presets/{presetId}/default` },
90448
+ operationId: "updateCliDefaultPreset",
90449
+ canonicalOperation: "cli.admin.preset.default.set",
90450
+ capability: "cli.admin.preset.write"
90451
+ }),
90452
+ ...direct(["admin preset unset-default"], {
90453
+ owner: "backend",
90454
+ authBoundary: "organization-oauth",
90455
+ quotaClass: "metadata",
90456
+ endpoint: { method: "DELETE", path: `${orgPath}/admin/presets/{presetId}/default` },
90457
+ operationId: "deleteCliDefaultPreset",
90458
+ canonicalOperation: "cli.admin.preset.default.unset",
90459
+ capability: "cli.admin.preset.write"
90460
+ }),
90461
+ ...direct(["admin tunnel status"], {
90462
+ owner: "backend",
90463
+ authBoundary: "organization-oauth",
90464
+ quotaClass: "metadata",
90465
+ endpoint: { method: "GET", path: `${orgPath}/admin/tunnel/status` },
90466
+ operationId: "getCliTunnelStatus",
90467
+ canonicalOperation: "cli.admin.tunnel.status.read",
90468
+ capability: "cli.admin.tunnel.read"
90469
+ }),
90470
+ ...candidate(["agent chat"], "chat", "organization-oauth", [
90471
+ "streaming-performance",
90472
+ "execution-permit-lifetime",
90473
+ "disconnect-cancel-recovery"
90474
+ ]),
90475
+ ...candidate(["admin agent export"], "backend", "organization-oauth", [
90476
+ "bounded-download",
90477
+ "partial-file-cleanup",
90478
+ "authorization-audit"
90479
+ ]),
90480
+ ...candidate(["skill upload", "skill download", "admin skill upload", "admin skill download"], "backend", "organization-oauth", [
90481
+ "archive-size-mime-validation",
90482
+ "presigned-host-policy",
90483
+ "abort-complete-recovery"
90484
+ ]),
90485
+ ...candidate([
90486
+ "admin skill github inspect",
90487
+ "admin skill github import",
90488
+ "admin skill github sync"
90489
+ ], "backend", "organization-oauth", [
90490
+ "external-timeout",
90491
+ "repository-size-limit",
90492
+ "duplicate-import-protection",
90493
+ "credential-redaction"
90494
+ ]),
90495
+ ...candidate([
90496
+ "admin skill github credentials set",
90497
+ "admin skill github credentials clear"
90498
+ ], "backend", "organization-oauth", [
90499
+ "secret-redaction",
90500
+ "rotation-revoke-audit"
90501
+ ]),
90502
+ ...candidate(["drive upload", "drive download"], "backend", "organization-oauth", [
90503
+ "byte-timeout-bound",
90504
+ "presigned-host-policy",
90505
+ "storage-quota",
90506
+ "partial-file-cleanup"
90507
+ ]),
90508
+ ...candidate(["chat send"], "chat", "organization-oauth", [
90509
+ "conversation-idempotency",
90510
+ "paid-execution-deduplication",
90511
+ "timeout-cancel-recovery"
90512
+ ]),
90513
+ ...candidate(["integration test"], "backend", "organization-oauth", [
90514
+ "external-timeout",
90515
+ "credential-redaction"
90516
+ ]),
90517
+ ...candidate(["admin integration update", "admin integration delete"], "backend", "organization-oauth", [
90518
+ "typed-contract",
90519
+ "credential-redaction",
90520
+ "mutation-idempotency"
90521
+ ]),
90522
+ ...candidate(["automation run", "automation cancel", "automation webhook-regen"], "backend", "organization-oauth", [
90523
+ "operation-idempotency",
90524
+ "state-transition-validation",
90525
+ "execution-quota",
90526
+ "secret-rotation"
90527
+ ]),
90528
+ ...candidate(["admin preset regen-key", "admin preset regen-static-key"], "backend", "organization-oauth", [
90529
+ "key-redaction",
90530
+ "rotation-audit",
90531
+ "retry-rollback-safety"
90532
+ ]),
90533
+ ...candidate(["admin tunnel config", "admin tunnel token"], "backend", "organization-oauth", [
90534
+ "sensitive-output-policy",
90535
+ "token-ttl-redaction",
90536
+ "audit"
90537
+ ]),
90538
+ {
90539
+ command: "model-exec image generate",
90540
+ tier: "DEFERRED",
90541
+ owner: "chat",
90542
+ authBoundary: "organization-oauth",
90543
+ quotaClass: "endpoint-guard",
90544
+ availability: "DEFERRED",
90545
+ capability: "cli.model.image.generate",
90546
+ requiredGates: ["async-job-lifecycle", "artifact-ttl", "my-drive-output", "cost-reservation"]
90547
+ },
90548
+ ...fixedBoundary(["auth login", "auth refresh"], "STANDARD_OAUTH", "backend", "standard-oauth"),
90549
+ ...fixedBoundary([
90550
+ "auth status",
90551
+ "auth logout",
90552
+ "config set",
90553
+ "config status",
90554
+ "org current"
90555
+ ], "LOCAL_ONLY", "desktop", "local"),
90556
+ ...fixedBoundary(["install", "run", "tunnel"], "EXISTING_NATIVE", "native", "native"),
90557
+ ...fixedBoundary(["logs"], "INTERNAL_HIDDEN", "native", "hidden")
90558
+ ];
90559
+
90560
+ const CUSTOMER_AVAILABILITIES = /* @__PURE__ */ new Set([
90561
+ "IMPLEMENTED",
90562
+ "AVAILABLE"
90563
+ ]);
90564
+ const isCustomerAvailable = (entry) => CUSTOMER_AVAILABILITIES.has(entry.availability);
90565
+ const normalizeCliArgCase = (arg) => arg.toLowerCase();
90566
+ const commandSegments = (command) => command.split(" ");
90567
+ const PROD_DISABLED_BUILT_INS = /* @__PURE__ */ new Set(["--completions", "--wizard"]);
90568
+ const isCommandPrefix = (entry, args) => {
90569
+ const segments = commandSegments(entry.command);
90570
+ return segments.length <= args.length && segments.every((segment, index) => args[index] === segment);
90571
+ };
90572
+ const commandPathBeforeOptions = (args) => args.slice(0, args.findIndex((arg) => arg.startsWith("-")) === -1 ? args.length : args.findIndex((arg) => arg.startsWith("-")));
90573
+ const formatUnavailableMessage = (command) => `Command "aipctl ${command}" is not available in this aipctl release. Run "aipctl --help" to see supported commands.`;
90574
+ const formatUnavailableOptionMessage = (option) => `Option "aipctl ${option}" is not available in this aipctl release. Run "aipctl --help" to see supported commands.`;
90575
+ const commandArgsForAvailability = (args) => {
90576
+ const commandArgs = [];
90577
+ for (let index = 0; index < args.length; index += 1) {
90578
+ const arg = args[index];
90579
+ if (arg === "--log-level") {
90580
+ index += 1;
90581
+ continue;
90582
+ }
90583
+ commandArgs.push(arg);
90584
+ }
90585
+ return commandArgs;
90586
+ };
90587
+ const getUnavailableCommandMessage = (args, buildEnv) => {
90588
+ if (buildEnv !== "prod" || args.length === 0) {
90589
+ return null;
90590
+ }
90591
+ const normalizedArgs = args.map(normalizeCliArgCase);
90592
+ const disabledBuiltIn = normalizedArgs.find((arg) => PROD_DISABLED_BUILT_INS.has(arg));
90593
+ if (disabledBuiltIn) {
90594
+ return formatUnavailableOptionMessage(disabledBuiltIn);
90595
+ }
90596
+ const commandArgs = commandArgsForAvailability(normalizedArgs);
90597
+ const entry = commandManifest.filter((candidate) => isCommandPrefix(candidate, commandArgs)).sort((left, right) => commandSegments(right.command).length - commandSegments(left.command).length).at(0);
90598
+ if (entry) {
90599
+ return isCustomerAvailable(entry) ? null : formatUnavailableMessage(entry.command);
90600
+ }
90601
+ const path = commandPathBeforeOptions(commandArgs).join(" ");
90602
+ if (!path) {
90603
+ return null;
90604
+ }
90605
+ const descendants = commandManifest.filter(({ command }) => command.startsWith(`${path} `));
90606
+ if (descendants.length > 0 && descendants.every((candidate) => !isCustomerAvailable(candidate))) {
90607
+ return formatUnavailableMessage(path);
90608
+ }
90609
+ return null;
90610
+ };
90611
+
89806
90612
  const NOT_LOGGED_IN_MESSAGE = 'Not logged in. Please run "aipctl auth login" first.';
89807
90613
  const SESSION_EXPIRED_MESSAGE = 'Session expired. Run "aipctl auth login" to continue.';
89808
90614
 
@@ -89826,14 +90632,14 @@ class InvalidAppUrlError extends Error {
89826
90632
  this.rawValue = rawValue;
89827
90633
  }
89828
90634
  }
89829
- function isRecord$1(value) {
90635
+ function isRecord$2(value) {
89830
90636
  return typeof value === "object" && value !== null;
89831
90637
  }
89832
90638
  function optionalString$1(value) {
89833
90639
  return typeof value === "string" ? value : void 0;
89834
90640
  }
89835
90641
  function parseCurrentOrganization(value) {
89836
- if (!isRecord$1(value)) {
90642
+ if (!isRecord$2(value)) {
89837
90643
  return void 0;
89838
90644
  }
89839
90645
  const id = optionalString$1(value["id"]);
@@ -89845,7 +90651,7 @@ function parseCurrentOrganization(value) {
89845
90651
  return { id, slug, name };
89846
90652
  }
89847
90653
  function normalizeLoadedConfig(value) {
89848
- if (!isRecord$1(value)) {
90654
+ if (!isRecord$2(value)) {
89849
90655
  return {};
89850
90656
  }
89851
90657
  return {
@@ -92079,11 +92885,11 @@ const CREDENTIALS_FILE = path__namespace.join(CONFIG_DIR$1, "credentials.json");
92079
92885
  const CREDENTIALS_LOCK_FILE = path__namespace.join(CONFIG_DIR$1, "credentials.lock");
92080
92886
  class CredentialServiceTag extends Tag$1("CredentialService")() {
92081
92887
  }
92082
- function isNonEmptyString(value) {
92888
+ function isNonEmptyString$1(value) {
92083
92889
  return typeof value === "string" && value.length > 0;
92084
92890
  }
92085
92891
  function hasOAuthClient(credentials) {
92086
- return isNonEmptyString(credentials?.clientId);
92892
+ return isNonEmptyString$1(credentials?.clientId);
92087
92893
  }
92088
92894
  function isAccessTokenExpired(credentials, bufferMs = 0, now = Date.now()) {
92089
92895
  if (!credentials?.expiresAt) {
@@ -92092,13 +92898,13 @@ function isAccessTokenExpired(credentials, bufferMs = 0, now = Date.now()) {
92092
92898
  return credentials.expiresAt - bufferMs <= now;
92093
92899
  }
92094
92900
  function hasValidRefreshToken(credentials, now) {
92095
- return isNonEmptyString(credentials.refreshToken) && (credentials.refreshExpiresAt === void 0 || credentials.refreshExpiresAt > now);
92901
+ return isNonEmptyString$1(credentials.refreshToken) && (credentials.refreshExpiresAt === void 0 || credentials.refreshExpiresAt > now);
92096
92902
  }
92097
92903
  function getCredentialAuthStatus(credentials, now = Date.now(), options = {}) {
92098
92904
  if (!hasOAuthClient(credentials)) {
92099
92905
  return "missing";
92100
92906
  }
92101
- const needsAccessRefresh = options.forceRefresh || !isNonEmptyString(credentials.accessToken) || isAccessTokenExpired(credentials, options.accessExpiryBufferMs ?? 0, now);
92907
+ const needsAccessRefresh = options.forceRefresh || !isNonEmptyString$1(credentials.accessToken) || isAccessTokenExpired(credentials, options.accessExpiryBufferMs ?? 0, now);
92102
92908
  if (!needsAccessRefresh) {
92103
92909
  return "authenticated";
92104
92910
  }
@@ -93094,7 +93900,7 @@ function trimTrailingSlash(value) {
93094
93900
  function toError$1(error, fallbackMessage) {
93095
93901
  return error instanceof Error ? new Error(maskSensitiveText(error.message)) : new Error(maskSensitiveText(fallbackMessage));
93096
93902
  }
93097
- function isRecord(value) {
93903
+ function isRecord$1(value) {
93098
93904
  return typeof value === "object" && value !== null;
93099
93905
  }
93100
93906
  function optionalString(value) {
@@ -93104,7 +93910,7 @@ function optionalNumber(value) {
93104
93910
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
93105
93911
  }
93106
93912
  function parseOAuthTokenResponse(value) {
93107
- if (!isRecord(value)) {
93913
+ if (!isRecord$1(value)) {
93108
93914
  throw new OAuthRequestError("OAuth token response was not a JSON object", void 0, "invalid_token_response");
93109
93915
  }
93110
93916
  const accessToken = optionalString(value["access_token"]);
@@ -93633,6 +94439,55 @@ async function acquire() {
93633
94439
  }
93634
94440
  }
93635
94441
 
94442
+ const SERVER_CAPABILITY_SCHEMA_VERSION = 1;
94443
+ class ServerCapabilityError extends Error {
94444
+ code;
94445
+ constructor(code, message) {
94446
+ super(message);
94447
+ this.name = "ServerCapabilityError";
94448
+ this.code = code;
94449
+ }
94450
+ }
94451
+ function parseEnabledServerOperations(value) {
94452
+ if (!isRecord(value) || value["schemaVersion"] !== SERVER_CAPABILITY_SCHEMA_VERSION) {
94453
+ throw new ServerCapabilityError(
94454
+ "CLI_CAPABILITIES_INCOMPATIBLE",
94455
+ "The server returned an unsupported CLI capability schema."
94456
+ );
94457
+ }
94458
+ const enabledOperations = value["enabledOperations"];
94459
+ if (!Array.isArray(enabledOperations)) {
94460
+ throw new ServerCapabilityError(
94461
+ "CLI_CAPABILITIES_INCOMPATIBLE",
94462
+ "The server returned an invalid CLI capability operation list."
94463
+ );
94464
+ }
94465
+ const operationIds = /* @__PURE__ */ new Set();
94466
+ for (const operation of enabledOperations) {
94467
+ if (!isRecord(operation) || !isNonEmptyString(operation["operationId"]) || !isNonEmptyString(operation["capability"]) || operationIds.has(operation["operationId"])) {
94468
+ throw new ServerCapabilityError(
94469
+ "CLI_CAPABILITIES_INCOMPATIBLE",
94470
+ "The server returned an invalid CLI capability operation."
94471
+ );
94472
+ }
94473
+ operationIds.add(operation["operationId"]);
94474
+ }
94475
+ return operationIds;
94476
+ }
94477
+ function requireEnabledServerOperation(enabledOperations, operationId) {
94478
+ if (enabledOperations.has(operationId)) return;
94479
+ throw new ServerCapabilityError(
94480
+ "CLI_OPERATION_NOT_ENABLED",
94481
+ `CLI operation "${operationId}" is not enabled by the server.`
94482
+ );
94483
+ }
94484
+ function isRecord(value) {
94485
+ return typeof value === "object" && value !== null && !Array.isArray(value);
94486
+ }
94487
+ function isNonEmptyString(value) {
94488
+ return typeof value === "string" && value.length > 0;
94489
+ }
94490
+
93636
94491
  class ApiError extends TaggedError$1("ApiError") {
93637
94492
  }
93638
94493
  class NotLoggedInError extends TaggedError$1("NotLoggedInError") {
@@ -93939,7 +94794,7 @@ const parseSseStream = async (body) => {
93939
94794
  }
93940
94795
  throw new AgentChatStreamIncompleteError(hasDataEvent && sawOnlyTerminalEnvelope);
93941
94796
  };
93942
- const ApiServiceLive = effect$1(
94797
+ const makeApiServiceLive = (buildEnv) => effect$1(
93943
94798
  ApiServiceTag,
93944
94799
  gen(function* () {
93945
94800
  const configService = yield* ConfigService;
@@ -94056,6 +94911,34 @@ const ApiServiceLive = effect$1(
94056
94911
  });
94057
94912
  const baseUrl = () => loadConfiguredApiBaseUrl();
94058
94913
  const chatBaseUrl = () => loadConfiguredChatBaseUrl();
94914
+ const requireServerOperation = (operationId, token) => {
94915
+ if (buildEnv !== "prod") return _void;
94916
+ if (!releaseEnabledCommandOperationIds.has(operationId)) {
94917
+ return fail$3(createApiError({
94918
+ message: `CLI operation "${operationId}" is not enabled in this aipctl release.`,
94919
+ statusCode: 404,
94920
+ code: "CLI_OPERATION_NOT_ENABLED"
94921
+ }));
94922
+ }
94923
+ return gen(function* () {
94924
+ const response = yield* makeRequest(
94925
+ baseUrl,
94926
+ "/api/cli/v1/capabilities",
94927
+ token
94928
+ );
94929
+ yield* try_({
94930
+ try: () => {
94931
+ const enabledOperations = parseEnabledServerOperations(response);
94932
+ requireEnabledServerOperation(enabledOperations, operationId);
94933
+ },
94934
+ catch: (error) => createApiError({
94935
+ message: error instanceof Error ? error.message : "CLI server capability validation failed",
94936
+ statusCode: error instanceof ServerCapabilityError && error.code === "CLI_OPERATION_NOT_ENABLED" ? 404 : 503,
94937
+ code: error instanceof ServerCapabilityError ? error.code : "CLI_CAPABILITIES_INCOMPATIBLE"
94938
+ })
94939
+ });
94940
+ });
94941
+ };
94059
94942
  const subscribeAgentChatStream = (orgSlug, conversationId, token) => gen(function* () {
94060
94943
  const resolvedChatBaseUrl = yield* requireChatBaseUrlEffect();
94061
94944
  const path = `/api/${encodeURIComponent(orgSlug)}/conversations/${encodeURIComponent(conversationId)}/stream`;
@@ -94122,11 +95005,13 @@ const ApiServiceLive = effect$1(
94122
95005
  return {
94123
95006
  listOrganizations: () => gen(function* () {
94124
95007
  const token = yield* getAccessToken();
94125
- return yield* makeRequest(baseUrl, "/api/web/organizations", token);
95008
+ yield* requireServerOperation("listCliOrganizations", token);
95009
+ return yield* makeRequest(baseUrl, "/api/cli/v1/organizations", token);
94126
95010
  }),
94127
95011
  getOrganization: (slug) => gen(function* () {
94128
95012
  const token = yield* getAccessToken();
94129
- const orgs = yield* makeRequest(baseUrl, "/api/web/organizations", token);
95013
+ yield* requireServerOperation("listCliOrganizations", token);
95014
+ const orgs = yield* makeRequest(baseUrl, "/api/cli/v1/organizations", token);
94130
95015
  const org = orgs.find((o) => o.slug === slug);
94131
95016
  if (!org) {
94132
95017
  return yield* fail$3(
@@ -94465,7 +95350,8 @@ const ApiServiceLive = effect$1(
94465
95350
  // Phase 4: Monitoring
94466
95351
  listOrgMembers: (orgSlug) => gen(function* () {
94467
95352
  const token = yield* getAccessToken();
94468
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/members/detail`;
95353
+ yield* requireServerOperation("listCliOrganizationMembers", token);
95354
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/members`;
94469
95355
  const raw = yield* makeRequest(baseUrl, path, token);
94470
95356
  return {
94471
95357
  members: raw.members.map((member) => ({
@@ -94481,22 +95367,24 @@ const ApiServiceLive = effect$1(
94481
95367
  yield* requireChatBaseUrlEffect();
94482
95368
  const token = yield* getAccessToken();
94483
95369
  const path = `/api/${encodeURIComponent(orgSlug)}/models`;
94484
- const res = yield* makeRequest(chatBaseUrl, path, token);
94485
- return res.models.map((id) => ({
95370
+ const response = yield* makeRequest(chatBaseUrl, path, token);
95371
+ return response.models.map((id) => ({
94486
95372
  id,
94487
- ...res.defaultModel === id ? { isDefault: true } : {}
95373
+ ...response.defaultModel === id ? { isDefault: true } : {}
94488
95374
  }));
94489
95375
  }),
94490
95376
  listModelExecModels: (orgSlug) => gen(function* () {
94491
95377
  yield* requireChatBaseUrlEffect();
94492
95378
  const token = yield* getAccessToken();
94493
- const path = `/api/${encodeURIComponent(orgSlug)}/cli/model-exec/models`;
95379
+ yield* requireServerOperation("listCliModelExecModels", token);
95380
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/model-exec/models`;
94494
95381
  return yield* makeRequest(chatBaseUrl, path, token);
94495
95382
  }),
94496
95383
  executeModelExecChat: (orgSlug, body) => gen(function* () {
94497
95384
  yield* requireChatBaseUrlEffect();
94498
95385
  const token = yield* getAccessToken();
94499
- const path = `/api/${encodeURIComponent(orgSlug)}/cli/model-exec/chat`;
95386
+ yield* requireServerOperation("createCliModelChatExecution", token);
95387
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/model-exec/chat`;
94500
95388
  return yield* makeRequest(chatBaseUrl, path, token, {
94501
95389
  method: "POST",
94502
95390
  body
@@ -94637,7 +95525,8 @@ const ApiServiceLive = effect$1(
94637
95525
  // Phase 6: Auth enhancements
94638
95526
  getMe: () => gen(function* () {
94639
95527
  const token = yield* getAccessToken();
94640
- return yield* makeRequest(baseUrl, "/api/web/me", token);
95528
+ yield* requireServerOperation("getCliMe", token);
95529
+ return yield* makeRequest(baseUrl, "/api/cli/v1/me", token);
94641
95530
  }),
94642
95531
  refreshToken: () => refreshAccessToken({ force: true }),
94643
95532
  // Phase 7: Chat (read-only)
@@ -94818,12 +95707,14 @@ const ApiServiceLive = effect$1(
94818
95707
  // Org capabilities & user settings
94819
95708
  getOrgCapabilities: (orgSlug) => gen(function* () {
94820
95709
  const token = yield* getAccessToken();
94821
- const path = `/api/web/organizations/slug/${encodeURIComponent(orgSlug)}/capabilities`;
95710
+ yield* requireServerOperation("getCliOrganizationCapabilities", token);
95711
+ const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/capabilities`;
94822
95712
  return yield* makeRequest(baseUrl, path, token);
94823
95713
  }),
94824
95714
  getUserSettings: () => gen(function* () {
94825
95715
  const token = yield* getAccessToken();
94826
- return yield* makeRequest(baseUrl, "/api/web/user/settings", token);
95716
+ yield* requireServerOperation("getCliUserSettings", token);
95717
+ return yield* makeRequest(baseUrl, "/api/cli/v1/me/settings", token);
94827
95718
  }),
94828
95719
  // Tunnel management
94829
95720
  getTunnelStatus: (orgSlug) => gen(function* () {
@@ -94940,6 +95831,7 @@ const ApiServiceLive = effect$1(
94940
95831
  };
94941
95832
  })
94942
95833
  );
95834
+ const ApiServiceLive = makeApiServiceLive(BUILD_ENV);
94943
95835
  const ApiService = ApiServiceTag;
94944
95836
 
94945
95837
  const orgOption = text("org").pipe(
@@ -99713,9 +100605,11 @@ const generateCommand = make$4(
99713
100605
  "Generate an image once and save the first output artifact (5-minute timeout)"
99714
100606
  )
99715
100607
  );
100608
+ const imageCommandDescription = "Run image-generation model-exec commands";
100609
+ const imageSubcommands = [generateCommand];
99716
100610
  const imageCommand = make$4("image", {}).pipe(
99717
- withDescription("Run image-generation model-exec commands"),
99718
- withSubcommands([generateCommand])
100611
+ withDescription(imageCommandDescription),
100612
+ withSubcommands(imageSubcommands)
99719
100613
  );
99720
100614
  const resolveImageRequest = (model, prompt, input) => gen(function* () {
99721
100615
  if (isSome(input)) {
@@ -100567,6 +101461,8 @@ const HELP_GROUPS = [
100567
101461
  { path: ["drive"], description: driveCommandDescription, subcommands: driveSubcommands },
100568
101462
  { path: ["integration"], description: integrationCommandDescription, subcommands: integrationSubcommands },
100569
101463
  { path: ["model"], description: modelCommandDescription, subcommands: modelSubcommands },
101464
+ { path: ["model-exec"], description: modelExecCommandDescription, subcommands: modelExecSubcommands },
101465
+ { path: ["model-exec", "image"], description: imageCommandDescription, subcommands: imageSubcommands },
100570
101466
  { path: ["org"], description: orgCommandDescription, subcommands: orgSubcommands },
100571
101467
  { path: ["skill"], description: skillCommandDescription, subcommands: skillSubcommands },
100572
101468
  { path: ["admin", "org"], description: adminOrgCommandDescription, subcommands: adminOrgSubcommands },
@@ -100593,16 +101489,22 @@ const getCommandName = (command) => {
100593
101489
  }
100594
101490
  return name;
100595
101491
  };
100596
- const formatCommandList = (path, subcommands) => subcommands.map((command) => ` - ${formatCanonicalPath([...path, getCommandName(command)])}`).join("\n");
101492
+ const hasCustomerAvailableCommand = (path) => {
101493
+ const commandPath = path.join(" ");
101494
+ return commandManifest.some(
101495
+ (entry) => isCustomerAvailable(entry) && (entry.command === commandPath || entry.command.startsWith(`${commandPath} `))
101496
+ );
101497
+ };
101498
+ const formatCommandList = (path, subcommands, options) => subcommands.map((command) => [...path, getCommandName(command)]).filter((commandPath) => !options.customerOnly || hasCustomerAvailableCommand(commandPath)).map((commandPath) => ` - ${formatCanonicalPath(commandPath)}`).join("\n");
100597
101499
  const getHelpPath = (args) => {
100598
101500
  const lastArg = args.at(-1);
100599
- if (!lastArg || !HELP_FLAGS$1.has(lastArg)) {
101501
+ if (!lastArg || !HELP_FLAGS$1.has(normalizeCliArgCase(lastArg))) {
100600
101502
  return null;
100601
101503
  }
100602
- const path = args.slice(0, -1);
101504
+ const path = args.slice(0, -1).map(normalizeCliArgCase);
100603
101505
  return path.every((segment) => !segment.startsWith("-")) ? path : null;
100604
101506
  };
100605
- const renderGroupHelp = ({ path, description, subcommands }) => {
101507
+ const renderGroupHelp = ({ path, description, subcommands }, options) => {
100606
101508
  const canonicalPath = formatCanonicalPath(path);
100607
101509
  const usageTarget = path.length === 0 ? "$ aipctl <command>" : `$ ${canonicalPath} <command>`;
100608
101510
  return [
@@ -100618,7 +101520,7 @@ const renderGroupHelp = ({ path, description, subcommands }) => {
100618
101520
  "",
100619
101521
  "COMMANDS",
100620
101522
  "",
100621
- formatCommandList(path, subcommands),
101523
+ formatCommandList(path, subcommands, options),
100622
101524
  "",
100623
101525
  "OPTIONS",
100624
101526
  "",
@@ -100628,13 +101530,13 @@ const renderGroupHelp = ({ path, description, subcommands }) => {
100628
101530
  ""
100629
101531
  ].join("\n");
100630
101532
  };
100631
- const renderPublicHelpForArgs = (args) => {
101533
+ const renderPublicHelpForArgs = (args, options = {}) => {
100632
101534
  const helpPath = getHelpPath(args);
100633
101535
  if (!helpPath) {
100634
101536
  return null;
100635
101537
  }
100636
101538
  const group = HELP_GROUPS.find(({ path }) => isSamePath(path, helpPath));
100637
- return group ? renderGroupHelp(group) : null;
101539
+ return group ? renderGroupHelp(group, options) : null;
100638
101540
  };
100639
101541
 
100640
101542
  const HELP_FLAGS = /* @__PURE__ */ new Set(["--help", "-h"]);
@@ -100665,7 +101567,13 @@ const runNativeHelpIfRequested = (args, options = {}) => {
100665
101567
  };
100666
101568
 
100667
101569
  const args = process.argv.slice(2);
100668
- const helpOutput = renderPublicHelpForArgs(args);
101570
+ const unavailableMessage = getUnavailableCommandMessage(args, BUILD_ENV);
101571
+ if (unavailableMessage) {
101572
+ process.stderr.write(`${unavailableMessage}
101573
+ `);
101574
+ process.exit(2);
101575
+ }
101576
+ const helpOutput = renderPublicHelpForArgs(args, { customerOnly: BUILD_ENV === "prod" });
100669
101577
  if (helpOutput) {
100670
101578
  process.stdout.write(`${helpOutput}
100671
101579
  `);
@@ -38,10 +38,10 @@
38
38
  | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
39
39
  | AUTH-01 | auth | `aipctl auth login` | `src/core/oauth.ts`: `discoverOAuthMetadata` → `registerCliOAuthClient` → `exchangeAuthorizationCode` | api + external browser | `GET /.well-known` → `POST /oauth2/register` → browser `GET /oauth2/authorize` → `POST /oauth2/token` | `/.well-known/oauth-authorization-server`, `/oauth2/register`, `/oauth2/authorize`, `/oauth2/token` | PKCE state/challenge, dynamic client registration body, auth code exchange form | `OAuthMetadata`, `OAuthClientRegistration`, `OAuthTokenResponse` → local `Credentials` | not found in current `resource/oas` for `oauth-authorization-server` / `/oauth2/register` / `/oauth2/token` | none | `oas-missing` | N/A | `legacy-exception` | owner=`backend/api OAuth server`; rationale=`login is required public auth flow but OAuth authorization-server/DCR/token contract is not in current OAS`; removal condition=`official OAuth server contract exists in resource/oas and independent generated contract`; incorporation plan=`add OAuth server metadata/register/token paths or dedicated auth contract fixture, then bind CLI parser/tests` | `AIP-PUB-05` | existing auth tests cover login helpers; needed contract snapshot for OAuth metadata/register/token paths |
40
40
  | AUTH-02 | auth | `aipctl auth refresh` | `ApiService.refreshToken` → `refreshAccessToken` → `src/core/oauth.ts#refreshOAuthToken` | api | `POST` | `/oauth2/token` | refresh token form body | refreshed local `Credentials` | not found in current `resource/oas` for `/oauth2/token` | none | `oas-missing` | N/A | `legacy-exception` | owner=`backend/api OAuth server`; rationale=`token refresh is required for session continuity but token endpoint is outside current OAS`; removal condition=`official OAuth token contract exists in resource/oas and independent generated contract`; incorporation plan=`same OAuth server contract as AUTH-01, plus refresh fixture` | `AIP-PUB-05` | existing `src/core/oauth.test.ts`, `src/core/api.test.ts`; needed token refresh path snapshot |
41
- | AUTH-03 | auth | `aipctl auth whoami` | `ApiService.getMe` | api | `GET` | `/api/web/me` | none | local `UserProfile` | `resource/oas/duplo-web.yaml` | `frontend/packages/api/src/out/user-types.ts#paths["/api/web/me"]` | `legacy-generated` | N/A | `keep` | none | N/A | existing `commands/auth/auth.test.ts`; needed user-types ref note only |
42
- | ORG-01 | org | `aipctl org list`, `aipctl org use` | `listOrganizations`, `getOrganization` | api | `GET` | `/api/web/organizations`; CLI `use` filters locally by slug after list call | none | local `Organization[]` / `Organization` | `resource/oas/duplo-web.yaml` | `frontend/packages/api/src/out/user-types.ts#paths["/api/web/organizations"]`, `#paths["/api/web/organizations/slug/{organizationSlug}"]` | `legacy-generated` | N/A | `keep` | none | N/A | existing `commands/org/org.test.ts`; needed slug lookup contract snapshot |
43
- | ORG-02 | org | `aipctl org capabilities`, `aipctl org settings`, `aipctl org exit` | `getOrgCapabilities`, `getUserSettings`, `exitOrg` | api | `GET`, `GET`, `POST` | `/api/web/organizations/slug/{organizationSlug}/capabilities`; `/api/web/user/settings`; `/api/web/organizations/slug/{organizationSlug}/exit` | none | local `OrgCapabilities`, `UserSettings`, `void` | capabilities: `resource/oas/modules/backend/organization/openapi.yaml`; settings/exit: `resource/oas/duplo-web.yaml` | capabilities `frontend/packages/api/src/out/modules/organization-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/capabilities"]`; settings/exit legacy `frontend/packages/api/src/out/user-types.ts#paths[...]` | `legacy-generated` | N/A | `keep` | none | N/A | existing org tests partial; needed capability/settings/exit smoke coverage |
44
- | P0-ORG-01 | org-member | `aipctl org members`; `aipctl admin org invite`, `aipctl admin org remove-member`, `aipctl admin org update-member-role` | `listOrgMembers`, `inviteOrgMembers`, `removeOrgMembers`, `updateOrgMemberRoles` | api | `GET`, `POST`, `DELETE`, `PUT` | `/api/web/organizations/slug/{organizationSlug}/members/detail`; `/invite`; `/members` | list uses detail status shape; invite body `{ emails, role: 'owner' | 'admin' | 'aiOperator' | 'member' }`; remove/update bodies `{ members: [{ email, status, userId? }] }` + update `role` | local `ListMembersResponse`, `InviteOrgMembersResponse`, `void`; mutation commands preload `listOrgMembers` for selection UX | latest role enum source: `resource/oas/modules/backend/_/components/schemas/OrganizationRoleEnum.yaml`; member status source: `resource/oas/modules/backend/organization/openapi.yaml`; legacy member list/mutation paths: `resource/oas/duplo-web.yaml` | latest refs: `frontend/packages/api/src/out/modules/backend-common-types.ts#OrganizationRoleEnum`, `frontend/packages/api/src/out/modules/organization-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/members/status"]`; legacy refs: `frontend/packages/api/src/out/user-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/invite"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/members"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/members/detail"]` | `legacy-generated` | `P0` | `legacy-exception` | owner=`backend app Organization API / duplo-web legacy OAS`; rationale=`public member list/admin flow kept for beta; role/status now align with current enum/status source while invite/remove/update still rely on legacy duplo-web member mutation contract`; removal condition=`independent contract includes member detail list plus invite/remove/update member mutations`; incorporation plan=`add resource/oas-based organization member admin contract, then remove legacy duplo-web refs and local fallback mapping` | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/org/members.test.ts`, `commands/org/org-member.test.ts`; covers detail path, lower-case role enum, failedInvitations, member mutation body |
41
+ | AUTH-03 | auth | `aipctl auth whoami` | `ApiService.getMe` | api | `GET` | `/api/cli/v1/me` | none | local `UserProfile` | `resource/oas/modules/backend/cli/openapi.yaml` | `backend/api/.../cli/generated/api/CliV1Api.kt#getCliMe` | `generated-ready` | N/A | `migrate` | none | N/A | `src/core/api.test.ts` verifies the dedicated path and bearer request; `commands/auth/auth.test.ts` covers command behavior |
42
+ | ORG-01 | org | `aipctl org list`, `aipctl org use`, `aipctl org select` | `listOrganizations`, `getOrganization` | api | `GET` | `/api/cli/v1/organizations`; `use/select` resolve locally from the returned list | none | local `Organization[]` / `Organization` | `resource/oas/modules/backend/cli/openapi.yaml` | `backend/api/.../cli/generated/api/CliV1Api.kt#listCliOrganizations` | `generated-ready` | N/A | `migrate` | none | N/A | `src/core/api.test.ts`, `commands/org/org.test.ts`; covers dedicated path, local slug selection, default/IP-blocked fields |
43
+ | ORG-02 | org | `aipctl org capabilities`, `aipctl org settings`, `aipctl org exit` | `getOrgCapabilities`, `getUserSettings`, `exitOrg` | api | `GET`, `GET`, `POST` | organization v1 `/api/cli/v1/organizations/{organizationSlug}/capabilities`; user-global v1 `/api/cli/v1/me/settings`; legacy `/api/web/organizations/slug/{organizationSlug}/exit` | none | local `OrgCapabilities`, `UserSettings`, `void` | read paths: `resource/oas/modules/backend/cli/openapi.yaml`; exit: `resource/oas/duplo-web.yaml` | read generated `CliOrganizationApi`/`CliV1Api`; exit legacy generated | `legacy-generated` | N/A | `migrate` | owner=`backend`; rationale=`capabilities is organization-owned, settings remains user-global, and exit remains a Wave B mutation`; removal condition=`exit receives its dedicated v1 mutation contract`; incorporation plan=`preserve current membership authorization and non-replay behavior` | task 3.3 | `src/core/api.test.ts` verifies v1 read paths and settings ownership; org tests cover response/error behavior |
44
+ | P0-ORG-01 | org-member | `aipctl org members`; `aipctl admin org invite`, `aipctl admin org remove-member`, `aipctl admin org update-member-role` | `listOrgMembers`, `inviteOrgMembers`, `removeOrgMembers`, `updateOrgMemberRoles` | api | `GET`, `POST`, `DELETE`, `PUT` | list v1 `/api/cli/v1/organizations/{organizationSlug}/members`; mutations remain legacy `/invite`; `/members` | list uses stable CLI member response; mutation bodies preserve `{ emails, role }` and `{ members, role? }` | local `ListMembersResponse`, `InviteOrgMembersResponse`, `void` | list: `resource/oas/modules/backend/cli/openapi.yaml`; mutation: `resource/oas/duplo-web.yaml` | list generated `CliOrganizationApi`; mutation legacy generated | `legacy-generated` | `P0` | `legacy-exception` | owner=`backend`; rationale=`member read is migrated while admin mutations remain Wave B`; removal condition=`invite/remove/role receive dedicated v1 contracts`; incorporation plan=`reuse current admin authorization, audit, stale target validation, and non-replay semantics` | task 3.3 | `src/core/api.test.ts`, `commands/org/members.test.ts`, `commands/org/org-member.test.ts`; covers v1 member read and legacy mutation bodies |
45
45
  | P0-ORG-02 | org-admin | hidden from public beta (`aipctl admin org invite-link`, `gen-invite-link`, `revoke-invite-link` removed from command tree) | removed from public surface | api | `GET`, `POST`, `DELETE` | previously `/api/web/organizations/slug/{organizationSlug}/invite/link` | none | hidden | latest: `resource/oas/modules/backend/organization/openapi.yaml` (`/invite/link/v2`); legacy: `resource/oas/duplo-web.yaml` (`/invite/link`) | latest `frontend/packages/api/src/out/modules/organization-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/invite/link/v2"]`; legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/invite/link"]` | `oas-source-only` | `P0` | `hide` | owner=`backend organization module`; rationale=`v2 exists but current CLI UX contract for GET/DELETE parity is not approved for public beta`; removal condition=`public beta continues hiding until a reviewed v2 CLI UX contract exists`; incorporation plan=`reintroduce only after independent organization contract/build and public UX review` | N/A | updated admin org help smoke + command-tree regression to ensure trio is absent |
46
46
  | SKILL-01 | skill | `aipctl skill list`, `aipctl skill get`, `aipctl skill delete` | `listSkills`, `getSkill`, `deleteSkill` | api | `GET`, `GET`, `DELETE` | `/api/web/organizations/slug/{organizationSlug}/skills`; `/skills/{skillId}` | query `{ count,cursor,search }`; detail query `{ maxFiles }` | local `ListSkillsResponse`, `SkillDetail`, `void` | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/skills"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/skills/{skillId}"]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/skill/*.test.ts`; needed path/type snapshot once independent generation exists |
47
47
  | SKILL-02 | skill | `aipctl skill upload` | `createUploadUrl` → `uploadToS3` → `completeUpload` (`abortUpload` on failure) | api + external | `POST` → `PUT` → `POST` | `/skills/upload-url`; external presigned `uploadUrl`; `/skills/{skillId}/complete` | local upload request `{ filename,fileSize,mimeType }`, file buffer, complete body `{ overwrite }` | `CreateSkillUploadUrlResponse`, external `void`, `CompleteSkillUploadResponse` | `resource/oas/modules/backend/organization/skills/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-skills-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/skills/upload-url"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/skills/{skillId}/complete"]` | `external-presigned` | N/A | `keep` | none | N/A | existing skill upload tests; needed presigned URL + complete path snapshot |
@@ -57,8 +57,9 @@
57
57
  | P0-DRIVE-01 | drive | `aipctl drive list`, `download`, `delete`, `mkdir`, `rename`, `usage` | `listDriveEntries`, `getDriveDownloadUrl`, `deleteDriveEntries`, `createDriveFolder`, `renameDriveEntry`, `getDriveUsage`, `downloadFromUrl` | api + external | `GET`, `POST`, `POST`, `POST`, `PATCH`, `GET`, external `GET` | `/drive/entries?count=200`; `/drive/entries/download-url`; `/drive/entries/delete`; `/drive/entries/{entryId}`; `/drive/usage` | official list `{ path, hasNext, nextCursor, items }`; delete body `{ entryIds[] }`; rename body `{ newName }`; download body `{ entryIds: [id] }` | official drive list/download DTOs + external file buffer | `resource/oas/modules/backend/organization/storage/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-storage-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/download-url"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/{entryId}"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/delete"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/usage"]` | `generated-ready` | `P0` | `migrate` | none | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/drive/drive.test.ts`; covers paged list shape, batch download-url request, DTO field rename (`sizeBytes`, `modifiedAt`) |
58
58
  | P0-DRIVE-02 | drive | `aipctl drive upload` | `createDriveUploadUrl` → `uploadToS3` → `completeDriveUpload` | api + external | `POST` → `PUT` → `POST` | `/drive/entries/upload-url`; external presigned `uploadUrl`; `/drive/entries/{entryId}/complete` | official upload request `{ parentId: null, filename, fileSize, mimeType }` | official `CreateDriveUploadUrlResponse { id, filename, uploadUrl, headers }` then `void` | `resource/oas/modules/backend/organization/storage/openapi.yaml` | `frontend/packages/api/src/out/modules/organization-storage-types.ts#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/upload-url"]`, `#paths["/api/web/organizations/slug/{organizationSlug}/drive/entries/{entryId}/complete"]` | `generated-ready` | `P0` | `migrate` | none | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/drive/drive.test.ts`; covers `parentId: null` request and response `id`/`filename` usage |
59
59
  | P1-INT-01 | integration | `aipctl integration list`, `test`; `aipctl admin integration get`, `update`, `delete`, `tools`, `available` | `listIntegrations`, `testIntegration`, `getIntegration`, `updateIntegration`, `deleteIntegration`, `listIntegrationTools`, `listConfigurableIntegrations` | api | `GET`, `POST`, `GET`, `PUT`, `DELETE`, `GET`, `GET` | `/api/web/integrations/v2`; `/api/web/integration/{integrationId}/test`; `/api/web/admin/organizations/slug/{organizationSlug}/integrations/{integrationId}`; `/{integrationId}/tools`; `/configurable-integrations` | top-level list/test and admin detail/available now follow current/legacy OAS path+body+DTO where available; admin update/delete still accept untyped legacy mutation body/path until admin mutation contract lands | local `Integration`, `IntegrationDetail`, `IntegrationToolsResponse`, `ConfigurableIntegration[]` | legacy admin paths: `resource/oas/duplo-web.yaml`; partial modern source: `resource/oas/modules/backend/integration/openapi.yaml` (does not cover these admin list/CRUD/tools paths) | legacy `frontend/packages/api/src/out/user-types.ts#paths["/api/web/admin/organizations/slug/{organizationSlug}/integrations"]`, `#paths["/api/web/admin/organizations/slug/{organizationSlug}/configurable-integrations"]`; partial current `frontend/packages/api/src/out/modules/integration-types.ts` lacks these admin list/CRUD/tools paths | `legacy-generated` | `P1` | `legacy-exception` | owner=`backend app Integrations / duplo-web legacy OAS`; rationale=`public beta keeps integration list/test/admin detail/tools/available, but admin update/delete still lack an approved current contract outside legacy duplo-web`; removal condition=`independent contract covers user list/test plus admin CRUD/tools/available`; incorporation plan=`extend integration module or independent contract for list/test/admin CRUD/tools/available, then retire legacy path/body mappings and delete/update exception` | N/A | updated `src/core/api.test.ts`, `commands/integration/integration.test.ts`; covers v2 list query, test body `{ organizationSlug }`, admin detail/tools DTO fields, configurable wrapper unwrap, and pinned update/delete legacy paths |
60
- | P0-MODEL-01 | model | `aipctl model list` | `listModels` | chat | `GET` | `/api/{orgSlug}/models` | none | CLI maps official `{ models: string[], defaultModel? }` into `Model[]` with optional `isDefault` | `resource/oas/chat.yaml` | `frontend/packages/api/src/out/chat-types.ts#paths["/api/{orgSlug}/models"]` | `legacy-generated` | `P0` | `migrate` | none | `AIP-PUB-05` | updated `src/core/api.test.ts`, `commands/model/model.test.ts`; covers official path and string-array response mapping |
61
- | P1-MODEL-EXEC-01 | model-exec | `aipctl model-exec models`, `get`, `sample`, `chat`, `image generate` | `listModelExecModels`, `executeModelExecChat`, `executeModelExecImageGeneration`; image output uses `downloadFromUrl` | chat + external artifact URL | `GET`, `POST`, `POST`, external `GET` | `/api/{orgSlug}/cli/model-exec/models`; `/chat`; `/images/generations`; response `downloadUrl` | local `ModelExecChatRequest`, `ModelExecImageGenerationRequest`; Chat DTO source `chat/packages/chat/src/modules/cli-model-exec/interface/dto/cli-model-exec.dto.ts` | local `ModelExecModelCatalog`, `ModelExecChatResponse`, `ModelExecImageGenerationResponse`; image bytes from external URL | not found in current `resource/oas`; implemented by `chat/packages/chat/src/modules/cli-model-exec/interface/cli-model-exec.interface.controller.ts` | none | `oas-missing` | `P1` | `legacy-exception` | owner=`chat CLI Model Exec API`; rationale=`experimental public command is implemented with Chat zod DTOs but no current OAS path`; removal condition=`CLI model-exec paths and DTOs are published in the Chat contract`; incorporation plan=`add the three paths and schemas to the Chat OAS, generate an independent reference, then bind CLI DTO/tests` | `AIP-PUB-05` | existing `src/core/api.test.ts`, `commands/model-exec/model-exec.test.ts`, `commands/model-exec/progress.test.ts`; covers three paths, request bodies, required Chat DTO response fields, helper/progress behavior. Needed: image command response → external download → file write regression test |
60
+ | P0-MODEL-01 | model | `aipctl model list` | `listModels` | chat | `GET` | legacy `/api/{orgSlug}/models`; target `/api/cli/v1/organizations/{orgSlug}/models` | none | legacy `{ models: string[], defaultModel? }` is mapped into `Model[]` and preserves active standard, custom/BYOK, and `etc` catalog IDs | legacy source: `resource/oas/chat.yaml`; target CLI source not implemented | `frontend/packages/api/src/out/chat-types.ts#paths["/api/{orgSlug}/models"]` | `legacy-generated` | `P0` | `keep legacy until parity` | owner=`Chat ModelV1Controller/ModelInternalService`; rationale=`the current model-exec v1 catalog is backed by SharedModel and omits active custom/BYOK and etc models`; removal condition=`the dedicated CLI model catalog preserves legacy visible-model and default semantics with authorization and regression tests`; incorporation plan=`implement GET /api/cli/v1/organizations/{orgSlug}/models from the existing model domain, then mark model list IMPLEMENTED and retire the legacy path` | `AIP-PUB-05` | `src/core/api.test.ts` verifies the legacy path and preserves custom/BYOK and etc IDs; availability tests keep dev/local usable and prod disabled until parity |
61
+ | P1-MODEL-EXEC-01 | model-exec | `aipctl model-exec models`, `get`, `sample`, `chat` | `listModelExecModels`, `executeModelExecChat` | chat | `GET`, `POST` | `/api/cli/v1/organizations/{orgSlug}/model-exec/models`; `/chat` | local `ModelExecChatRequest`; Chat Zod/Swagger DTO source `chat/packages/chat/src/modules/cli-model-exec/interface/dto/cli-model-exec.dto.ts` | local `ModelExecModelCatalog`, `ModelExecChatResponse` | code-first OAS: `chat/packages/chat/src/modules/cli-model-exec/interface/cli-model-exec-v1.interface.controller.ts` | runtime Swagger contract | `oas-source-only` | `P1` | `migrate` | none | `AIP-PUB-05` | `src/core/api.test.ts` verifies both v1 paths; Chat controller contract test verifies operation IDs, request/response schemas, delegation to the existing service, and absence of a v1 image route |
62
+ | P1-MODEL-EXEC-02 | model-exec-image | `aipctl model-exec image generate` | `executeModelExecImageGeneration`; output uses `downloadFromUrl` | chat + external artifact URL | `POST`, external `GET` | legacy `/api/{orgSlug}/cli/model-exec/images/generations`; response `downloadUrl` | local `ModelExecImageGenerationRequest`; Chat DTO source `chat/packages/chat/src/modules/cli-model-exec/interface/dto/cli-model-exec.dto.ts` | local `ModelExecImageGenerationResponse`; image bytes from external URL | no GA OAS; legacy controller only | none | `oas-missing` | deferred | `hide` | owner=`chat CLI Model Exec API`; rationale=`synchronous image execution, external artifact lifetime, and cost recovery require the deferred async design`; removal condition=`image job/artifact/TTL/My Drive/cost gates pass`; incorporation plan=`publish a separate v1 image job contract only after the deferred design is implemented` | follow-up image hardening | existing image request/path test remains on the legacy route; customer capability must stay disabled |
62
63
  | USAGE-01 | usage | `aipctl admin usage credit`, `top-users`, `daily-graph`, `daily-users`, `mcp-top` | `getCreditStatistics`, `getCreditTopUsers`, `getCreditDailyGraph`, `getCreditDailyUsers`, `getMcpTopTools` | api | `GET` | `/api/web/admin/organizations/slug/{organizationSlug}/usage/...` | query `{ startDt,endDt,limit,pageNumber,pageSize,userId }` | local usage DTOs, `DailyUsageDetailsResponse.pagination { page,pageSize,total }` | `resource/oas/modules/backend/usage/openapi.yaml` | `frontend/packages/api/src/out/modules/usage-types.ts#paths[...]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/usage/usage.test.ts`; needed generated path snapshots |
63
64
  | AUDIT-01 | audit | `aipctl admin audit list`, `types` | `listAuditLogs`, `listAuditEventTypes` | api | `GET` | `/api/web/audit/organization/slug/{organizationSlug}`; `/api/web/audit/event/types` | query `{ eventType,page,pageSize }` | local `ListAuditResponse`, `AuditEventType[]` | `resource/oas/modules/backend/audit/openapi.yaml` | `frontend/packages/api/src/out/modules/backend-audit-types.ts#paths[...]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/audit/audit.test.ts`; needed generated path snapshots |
64
65
  | TUNNEL-01 | tunnel | `aipctl admin tunnel status`, `config`, `token` | `getTunnelStatus`, `getTunnelConfig`, `createTunnelToken` | api | `GET`, `GET`, `POST` | `/api/web/edge-tunnel/v2/organizations/slug/{organizationSlug}/status`; `/config`; `/token` | none | local `TunnelStatus`, `TunnelConfig`, `void` | `resource/oas/modules/backend/tunnel/openapi.yaml` | `frontend/packages/api/src/out/modules/tunnel-types.ts#paths[...]` | `generated-ready` | N/A | `keep` | none | N/A | existing `commands/tunnel/tunnel.test.ts`; needed v2 path snapshot |
@@ -83,7 +84,7 @@
83
84
  - `P1-PRESET-01` preset admin namespace/docs + legacy path tests done
84
85
  - `P1-SKILL-01` skill JSON/help/docs field sync done
85
86
  - `P1-CHAT-01` chat SSE fixture tests added for final/fallback/error cases
86
- - `P1-MODEL-EXEC-01` experimental CLI model-exec contract remains OAS-missing; current Chat controller/DTO and CLI path tests are recorded
87
+ - `P1-MODEL-EXEC-01` catalog/text moved to the dedicated v1 code-first OAS and CLI path; `P1-MODEL-EXEC-02` image remains deferred on the legacy route
87
88
 
88
89
  ## Manual notes
89
90
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aipctl",
3
- "version": "2026.9.3",
3
+ "version": "2026.9.5",
4
4
  "description": "QueryPie AIP and MCP CLI tool",
5
5
  "author": "QueryPie",
6
6
  "license": "UNLICENSED",
@@ -22,16 +22,16 @@
22
22
  "node": ">=24.18.0"
23
23
  },
24
24
  "metadata": {
25
- "contentHash": "5a3ddc0e9f4e7c9f5f7d034823c81d8de10b538b61bdf6f0b39dfd8d0b9d2669",
26
- "wrapperHash": "bf67d4c747818e036614ed04e2e492ba4d5c1f125ee2a4f73d1329a63a5c32a8",
27
- "nativeHash": "21a6d81389d87cc5729f7521c0c8abc753cc922638bc0044290a32ec229b2d51"
25
+ "contentHash": "41009029ba4ff1bb3ad17157d8af3499f5545ddf860fb1ea4803005b6a6ca026",
26
+ "wrapperHash": "15330253c506008f0676946c51659e0dfc616d42e8931180f47080a03b966203",
27
+ "nativeHash": "006b08c3e391f4571d9b7c0f12d684fe2448106259e7e0581b10f9be362452e9"
28
28
  },
29
29
  "optionalDependencies": {
30
- "aipctl-darwin-x64": "2026.9.3",
31
- "aipctl-darwin-arm64": "2026.9.3",
32
- "aipctl-linux-x64": "2026.9.3",
33
- "aipctl-linux-arm64": "2026.9.3",
34
- "aipctl-windows-x64": "2026.9.3",
35
- "aipctl-windows-arm64": "2026.9.3"
30
+ "aipctl-darwin-x64": "2026.9.1",
31
+ "aipctl-darwin-arm64": "2026.9.1",
32
+ "aipctl-linux-x64": "2026.9.1",
33
+ "aipctl-linux-arm64": "2026.9.1",
34
+ "aipctl-windows-x64": "2026.9.1",
35
+ "aipctl-windows-arm64": "2026.9.1"
36
36
  }
37
37
  }