aipctl 2026.10.2 → 2026.10.3
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 +123 -44
- package/docs/api-contract-inventory.md +6 -6
- package/package.json +3 -3
package/build/index.cjs
CHANGED
|
@@ -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.10.
|
|
89673
|
+
const VERSION = "2026.10.3".length > 0 ? "2026.10.3" : "0.0.0";
|
|
89674
89674
|
const BUILD_ENV = injectedBuildEnv;
|
|
89675
89675
|
const INCLUDE_NATIVE_LOGS = BUILD_ENV !== "prod";
|
|
89676
89676
|
|
|
@@ -89732,6 +89732,27 @@ const isNativeCommandEnabled = (command, includeLogs = INCLUDE_NATIVE_LOGS) => {
|
|
|
89732
89732
|
const FORCED_ARGS_SEPARATOR = "--";
|
|
89733
89733
|
const NATIVE_ROOT_COMMANDS = new Set(nativeCommandNames);
|
|
89734
89734
|
const trailingOptionSpecs = [
|
|
89735
|
+
...["list", "get", "create", "update", "rename", "delete", "set-default", "unset-default"].map((command) => ({
|
|
89736
|
+
command: ["admin", "preset", command],
|
|
89737
|
+
booleanOptions: new Set(command === "delete" ? ["--force", "-f"] : ["list", "get"].includes(command) ? ["--json"] : []),
|
|
89738
|
+
valueOptions: /* @__PURE__ */ new Set(["--org", ...command === "list" ? ["--page", "--pageSize"] : []]),
|
|
89739
|
+
explicitBooleanValues: true,
|
|
89740
|
+
booleanAliases: { "-f": "--force" }
|
|
89741
|
+
})),
|
|
89742
|
+
...["invite", "remove-member", "update-member-role"].map((command) => ({
|
|
89743
|
+
command: ["admin", "org", command],
|
|
89744
|
+
booleanOptions: new Set(command === "remove-member" ? ["--force", "-f"] : []),
|
|
89745
|
+
valueOptions: /* @__PURE__ */ new Set(["--org", ...command !== "remove-member" ? ["--role"] : []]),
|
|
89746
|
+
explicitBooleanValues: true,
|
|
89747
|
+
booleanAliases: { "-f": "--force" }
|
|
89748
|
+
})),
|
|
89749
|
+
{
|
|
89750
|
+
command: ["org", "exit"],
|
|
89751
|
+
booleanOptions: /* @__PURE__ */ new Set(["--force", "-f"]),
|
|
89752
|
+
valueOptions: /* @__PURE__ */ new Set(["--org"]),
|
|
89753
|
+
explicitBooleanValues: true,
|
|
89754
|
+
booleanAliases: { "-f": "--force" }
|
|
89755
|
+
},
|
|
89735
89756
|
...["list", "get"].map((command) => ({
|
|
89736
89757
|
command: ["automation", command],
|
|
89737
89758
|
booleanOptions: /* @__PURE__ */ new Set(["--json"]),
|
|
@@ -89885,7 +89906,20 @@ const implementedCommandOperationIds = /* @__PURE__ */ new Set([
|
|
|
89885
89906
|
"listCliDailyUsers",
|
|
89886
89907
|
"listCliTopMcpTools",
|
|
89887
89908
|
"listCliAuditLogs",
|
|
89888
|
-
"listCliAuditEventTypes"
|
|
89909
|
+
"listCliAuditEventTypes",
|
|
89910
|
+
"listCliPresets",
|
|
89911
|
+
"getCliPreset",
|
|
89912
|
+
"createCliPreset",
|
|
89913
|
+
"updateCliPreset",
|
|
89914
|
+
"updateCliPresetName",
|
|
89915
|
+
"deleteCliPreset",
|
|
89916
|
+
"updateCliDefaultPreset",
|
|
89917
|
+
"deleteCliDefaultPreset",
|
|
89918
|
+
"createCliOrganizationMemberInvitations",
|
|
89919
|
+
"deleteCliOrganizationMembers",
|
|
89920
|
+
"updateCliOrganizationMemberRoles",
|
|
89921
|
+
"deleteCliOrganizationMembership",
|
|
89922
|
+
"getCliTunnelStatus"
|
|
89889
89923
|
]);
|
|
89890
89924
|
const releaseEnabledCommandOperationIds = /* @__PURE__ */ new Set([
|
|
89891
89925
|
"listCliAgents",
|
|
@@ -89942,7 +89976,20 @@ const releaseEnabledCommandOperationIds = /* @__PURE__ */ new Set([
|
|
|
89942
89976
|
"listCliDailyUsers",
|
|
89943
89977
|
"listCliTopMcpTools",
|
|
89944
89978
|
"listCliAuditLogs",
|
|
89945
|
-
"listCliAuditEventTypes"
|
|
89979
|
+
"listCliAuditEventTypes",
|
|
89980
|
+
"listCliPresets",
|
|
89981
|
+
"getCliPreset",
|
|
89982
|
+
"createCliPreset",
|
|
89983
|
+
"updateCliPreset",
|
|
89984
|
+
"updateCliPresetName",
|
|
89985
|
+
"deleteCliPreset",
|
|
89986
|
+
"updateCliDefaultPreset",
|
|
89987
|
+
"deleteCliDefaultPreset",
|
|
89988
|
+
"createCliOrganizationMemberInvitations",
|
|
89989
|
+
"deleteCliOrganizationMembers",
|
|
89990
|
+
"updateCliOrganizationMemberRoles",
|
|
89991
|
+
"deleteCliOrganizationMembership",
|
|
89992
|
+
"getCliTunnelStatus"
|
|
89946
89993
|
]);
|
|
89947
89994
|
const direct = (commands, operation) => commands.map((command) => ({
|
|
89948
89995
|
command,
|
|
@@ -94948,6 +94995,14 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
94948
94995
|
});
|
|
94949
94996
|
const requireApiBaseUrlEffect = () => requireConfiguredBaseUrlEffect(loadConfiguredApiBaseUrl);
|
|
94950
94997
|
const requireChatBaseUrlEffect = () => requireConfiguredBaseUrlEffect(loadConfiguredChatBaseUrl);
|
|
94998
|
+
const presetPath = (presetId, orgSlug) => try_({
|
|
94999
|
+
try: () => {
|
|
95000
|
+
const slug = orgSlug ?? configService.load().currentOrganization?.slug;
|
|
95001
|
+
if (!slug) throw new Error("No organization selected. Use --org or select an organization.");
|
|
95002
|
+
return `/api/cli/v1/organizations/${encodeURIComponent(slug)}/admin/presets/${encodeURIComponent(presetId)}`;
|
|
95003
|
+
},
|
|
95004
|
+
catch: configuredBaseUrlError
|
|
95005
|
+
});
|
|
94951
95006
|
const toRefreshFailure = (error) => {
|
|
94952
95007
|
if (error instanceof ApiError || error instanceof NotLoggedInError) {
|
|
94953
95008
|
return error;
|
|
@@ -95908,7 +95963,8 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95908
95963
|
// Tunnel management
|
|
95909
95964
|
getTunnelStatus: (orgSlug) => gen(function* () {
|
|
95910
95965
|
const token = yield* getAccessToken();
|
|
95911
|
-
|
|
95966
|
+
yield* requireReleaseEnabledOperation("getCliTunnelStatus");
|
|
95967
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/admin/tunnel/status`;
|
|
95912
95968
|
return yield* makeRequest(baseUrl, path, token);
|
|
95913
95969
|
}),
|
|
95914
95970
|
getTunnelConfig: (orgSlug) => gen(function* () {
|
|
@@ -95922,49 +95978,60 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95922
95978
|
return yield* makeRequest(baseUrl, path, token, { method: "POST" });
|
|
95923
95979
|
}),
|
|
95924
95980
|
// Preset management
|
|
95925
|
-
listPresets: (orgSlug) => gen(function* () {
|
|
95981
|
+
listPresets: (orgSlug, page = 1, pageSize = 100) => gen(function* () {
|
|
95926
95982
|
const token = yield* getAccessToken();
|
|
95927
|
-
|
|
95928
|
-
|
|
95983
|
+
yield* requireReleaseEnabledOperation("listCliPresets");
|
|
95984
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(orgSlug)}/admin/presets?page=${page}&pageSize=${pageSize}`;
|
|
95985
|
+
const response = yield* makeRequest(baseUrl, path, token);
|
|
95986
|
+
return response.list;
|
|
95929
95987
|
}),
|
|
95930
|
-
getPreset: (presetId) => gen(function* () {
|
|
95988
|
+
getPreset: (presetId, orgSlug) => gen(function* () {
|
|
95931
95989
|
const token = yield* getAccessToken();
|
|
95932
|
-
|
|
95990
|
+
yield* requireReleaseEnabledOperation("getCliPreset");
|
|
95991
|
+
const path = yield* presetPath(presetId, orgSlug);
|
|
95933
95992
|
return yield* makeRequest(baseUrl, path, token);
|
|
95934
95993
|
}),
|
|
95935
95994
|
createPreset: (body) => gen(function* () {
|
|
95936
95995
|
const token = yield* getAccessToken();
|
|
95937
|
-
|
|
95996
|
+
yield* requireReleaseEnabledOperation("createCliPreset");
|
|
95997
|
+
const { organizationSlug, ...request } = body;
|
|
95998
|
+
const path = `/api/cli/v1/organizations/${encodeURIComponent(organizationSlug)}/admin/presets`;
|
|
95999
|
+
return yield* makeRequest(baseUrl, path, token, {
|
|
95938
96000
|
method: "POST",
|
|
95939
|
-
body
|
|
96001
|
+
body: request
|
|
95940
96002
|
});
|
|
95941
96003
|
}),
|
|
95942
|
-
updatePreset: (presetId, body) => gen(function* () {
|
|
96004
|
+
updatePreset: (presetId, body, orgSlug) => gen(function* () {
|
|
95943
96005
|
const token = yield* getAccessToken();
|
|
95944
|
-
|
|
96006
|
+
yield* requireReleaseEnabledOperation("updateCliPreset");
|
|
96007
|
+
const path = yield* presetPath(presetId, orgSlug);
|
|
95945
96008
|
return yield* makeRequest(baseUrl, path, token, { method: "PUT", body });
|
|
95946
96009
|
}),
|
|
95947
|
-
renamePreset: (presetId, name) => gen(function* () {
|
|
96010
|
+
renamePreset: (presetId, name, orgSlug) => gen(function* () {
|
|
95948
96011
|
const token = yield* getAccessToken();
|
|
95949
|
-
|
|
96012
|
+
yield* requireReleaseEnabledOperation("updateCliPresetName");
|
|
96013
|
+
const path = yield* presetPath(presetId, orgSlug);
|
|
95950
96014
|
return yield* makeRequest(baseUrl, path, token, {
|
|
95951
96015
|
method: "PATCH",
|
|
95952
96016
|
body: { name }
|
|
95953
96017
|
});
|
|
95954
96018
|
}),
|
|
95955
|
-
deletePreset: (presetId) => gen(function* () {
|
|
96019
|
+
deletePreset: (presetId, orgSlug) => gen(function* () {
|
|
95956
96020
|
const token = yield* getAccessToken();
|
|
95957
|
-
|
|
96021
|
+
yield* requireReleaseEnabledOperation("deleteCliPreset");
|
|
96022
|
+
const path = yield* presetPath(presetId, orgSlug);
|
|
95958
96023
|
return yield* makeRequest(baseUrl, path, token, { method: "DELETE", skipJsonParse: true });
|
|
95959
96024
|
}),
|
|
95960
|
-
setPresetAsDefault: (presetId) => gen(function* () {
|
|
96025
|
+
setPresetAsDefault: (presetId, orgSlug) => gen(function* () {
|
|
95961
96026
|
const token = yield* getAccessToken();
|
|
95962
|
-
|
|
95963
|
-
|
|
96027
|
+
yield* requireReleaseEnabledOperation("updateCliDefaultPreset");
|
|
96028
|
+
const path = `${yield* presetPath(presetId, orgSlug)}/default`;
|
|
96029
|
+
return yield* makeRequest(baseUrl, path, token, { method: "PUT" });
|
|
95964
96030
|
}),
|
|
95965
|
-
unsetPresetAsDefault: (presetId) => gen(function* () {
|
|
96031
|
+
unsetPresetAsDefault: (presetId, orgSlug) => gen(function* () {
|
|
95966
96032
|
const token = yield* getAccessToken();
|
|
95967
|
-
|
|
96033
|
+
yield* requireReleaseEnabledOperation("deleteCliDefaultPreset");
|
|
96034
|
+
const path = `${yield* presetPath(presetId, orgSlug)}/default`;
|
|
95968
96035
|
return yield* makeRequest(baseUrl, path, token, { method: "DELETE" });
|
|
95969
96036
|
}),
|
|
95970
96037
|
regenPresetKey: (presetId) => gen(function* () {
|
|
@@ -95980,29 +96047,33 @@ const makeApiServiceLive = (buildEnv) => effect$1(
|
|
|
95980
96047
|
// Org member management
|
|
95981
96048
|
inviteOrgMembers: (req) => gen(function* () {
|
|
95982
96049
|
const token = yield* getAccessToken();
|
|
95983
|
-
|
|
96050
|
+
yield* requireReleaseEnabledOperation("createCliOrganizationMemberInvitations");
|
|
96051
|
+
return yield* makeRequest(baseUrl, `/api/cli/v1/organizations/${encodeURIComponent(req.organizationSlug)}/members/invitations`, token, {
|
|
95984
96052
|
method: "POST",
|
|
95985
96053
|
body: { emails: req.emails, role: req.role }
|
|
95986
96054
|
});
|
|
95987
96055
|
}),
|
|
95988
96056
|
removeOrgMembers: (req) => gen(function* () {
|
|
95989
96057
|
const token = yield* getAccessToken();
|
|
95990
|
-
yield*
|
|
96058
|
+
yield* requireReleaseEnabledOperation("deleteCliOrganizationMembers");
|
|
96059
|
+
yield* makeRequest(baseUrl, `/api/cli/v1/organizations/${encodeURIComponent(req.organizationSlug)}/members`, token, {
|
|
95991
96060
|
method: "DELETE",
|
|
95992
96061
|
body: { members: req.members }
|
|
95993
96062
|
});
|
|
95994
96063
|
}),
|
|
95995
96064
|
updateOrgMemberRoles: (req) => gen(function* () {
|
|
95996
96065
|
const token = yield* getAccessToken();
|
|
95997
|
-
yield*
|
|
96066
|
+
yield* requireReleaseEnabledOperation("updateCliOrganizationMemberRoles");
|
|
96067
|
+
yield* makeRequest(baseUrl, `/api/cli/v1/organizations/${encodeURIComponent(req.organizationSlug)}/members/role`, token, {
|
|
95998
96068
|
method: "PUT",
|
|
95999
96069
|
body: { members: req.members, role: req.role }
|
|
96000
96070
|
});
|
|
96001
96071
|
}),
|
|
96002
96072
|
exitOrg: (slug) => gen(function* () {
|
|
96003
96073
|
const token = yield* getAccessToken();
|
|
96004
|
-
yield*
|
|
96005
|
-
|
|
96074
|
+
yield* requireReleaseEnabledOperation("deleteCliOrganizationMembership");
|
|
96075
|
+
yield* makeRequest(baseUrl, `/api/cli/v1/organizations/${encodeURIComponent(slug)}/membership`, token, {
|
|
96076
|
+
method: "DELETE"
|
|
96006
96077
|
});
|
|
96007
96078
|
}),
|
|
96008
96079
|
// Agent headless chat
|
|
@@ -96959,13 +97030,13 @@ const deleteCommand$4 = make$4(
|
|
|
96959
97030
|
{ id: idArg$7, org: orgOption, force: forceOption$5 },
|
|
96960
97031
|
({ id, org, force }) => gen(function* () {
|
|
96961
97032
|
const api = yield* ApiService;
|
|
96962
|
-
yield* resolveOrgSlug(org, api);
|
|
97033
|
+
const orgSlug = yield* resolveOrgSlug(org, api);
|
|
96963
97034
|
if (!force) {
|
|
96964
97035
|
yield* log(`Warning: This will permanently delete preset "${id}".`);
|
|
96965
97036
|
yield* log("Use --force (-f) to skip this confirmation.");
|
|
96966
97037
|
return;
|
|
96967
97038
|
}
|
|
96968
|
-
yield* api.deletePreset(id).pipe(
|
|
97039
|
+
yield* api.deletePreset(id, orgSlug).pipe(
|
|
96969
97040
|
catchTag(
|
|
96970
97041
|
"NotLoggedInError",
|
|
96971
97042
|
(e) => gen(function* () {
|
|
@@ -96998,8 +97069,8 @@ const getCommand$6 = make$4(
|
|
|
96998
97069
|
{ id: idArg$6, org: orgOption, json: jsonOption$h },
|
|
96999
97070
|
({ id, org, json }) => gen(function* () {
|
|
97000
97071
|
const api = yield* ApiService;
|
|
97001
|
-
yield* resolveOrgSlug(org, api);
|
|
97002
|
-
const preset = yield* api.getPreset(id).pipe(
|
|
97072
|
+
const orgSlug = yield* resolveOrgSlug(org, api);
|
|
97073
|
+
const preset = yield* api.getPreset(id, orgSlug).pipe(
|
|
97003
97074
|
catchTag(
|
|
97004
97075
|
"NotLoggedInError",
|
|
97005
97076
|
(e) => gen(function* () {
|
|
@@ -97054,11 +97125,19 @@ function formatPresetListPrompt(prompt) {
|
|
|
97054
97125
|
}
|
|
97055
97126
|
const listCommand$9 = make$4(
|
|
97056
97127
|
"list",
|
|
97057
|
-
{
|
|
97058
|
-
|
|
97128
|
+
{
|
|
97129
|
+
org: orgOption,
|
|
97130
|
+
json: jsonOption$g,
|
|
97131
|
+
page: integer("page").pipe(withDescription$3("Page number, starting at 1"), withDefault(1)),
|
|
97132
|
+
pageSize: integer("pageSize").pipe(withDescription$3("Presets per page (1\u2013100)"), withDefault(100))
|
|
97133
|
+
},
|
|
97134
|
+
({ org, json, page, pageSize }) => gen(function* () {
|
|
97135
|
+
if (page < 1 || pageSize < 1 || pageSize > 100) {
|
|
97136
|
+
return yield* fail$3(new ApiError({ message: "Use --page 1 or higher and --pageSize between 1 and 100." }));
|
|
97137
|
+
}
|
|
97059
97138
|
const api = yield* ApiService;
|
|
97060
97139
|
const orgSlug = yield* resolveOrgSlug(org, api);
|
|
97061
|
-
const result = yield* api.listPresets(orgSlug).pipe(
|
|
97140
|
+
const result = yield* api.listPresets(orgSlug, page, pageSize).pipe(
|
|
97062
97141
|
catchTag(
|
|
97063
97142
|
"NotLoggedInError",
|
|
97064
97143
|
(e) => gen(function* () {
|
|
@@ -97079,10 +97158,10 @@ const listCommand$9 = make$4(
|
|
|
97079
97158
|
return;
|
|
97080
97159
|
}
|
|
97081
97160
|
if (result.length === 0) {
|
|
97082
|
-
yield* log(
|
|
97161
|
+
yield* log(`No presets found on page ${page}.`);
|
|
97083
97162
|
return;
|
|
97084
97163
|
}
|
|
97085
|
-
yield* log(`Presets in organization "${orgSlug}":
|
|
97164
|
+
yield* log(`Presets in organization "${orgSlug}" (page ${page}):
|
|
97086
97165
|
`);
|
|
97087
97166
|
for (const preset of result) {
|
|
97088
97167
|
const defaultMark = preset.isDefault ? " (default)" : "";
|
|
@@ -97158,8 +97237,8 @@ const renameCommand$1 = make$4(
|
|
|
97158
97237
|
{ id: idArg$3, name: nameArg$1, org: orgOption },
|
|
97159
97238
|
({ id, name, org }) => gen(function* () {
|
|
97160
97239
|
const api = yield* ApiService;
|
|
97161
|
-
yield* resolveOrgSlug(org, api);
|
|
97162
|
-
yield* api.renamePreset(id, name).pipe(
|
|
97240
|
+
const orgSlug = yield* resolveOrgSlug(org, api);
|
|
97241
|
+
yield* api.renamePreset(id, name, orgSlug).pipe(
|
|
97163
97242
|
catchTag(
|
|
97164
97243
|
"NotLoggedInError",
|
|
97165
97244
|
(e) => gen(function* () {
|
|
@@ -97185,8 +97264,8 @@ const setDefaultCommand = make$4(
|
|
|
97185
97264
|
{ id: idArg$2, org: orgOption },
|
|
97186
97265
|
({ id, org }) => gen(function* () {
|
|
97187
97266
|
const api = yield* ApiService;
|
|
97188
|
-
yield* resolveOrgSlug(org, api);
|
|
97189
|
-
yield* api.setPresetAsDefault(id).pipe(
|
|
97267
|
+
const orgSlug = yield* resolveOrgSlug(org, api);
|
|
97268
|
+
yield* api.setPresetAsDefault(id, orgSlug).pipe(
|
|
97190
97269
|
catchTag(
|
|
97191
97270
|
"NotLoggedInError",
|
|
97192
97271
|
(e) => gen(function* () {
|
|
@@ -97212,8 +97291,8 @@ const unsetDefaultCommand = make$4(
|
|
|
97212
97291
|
{ id: idArg$1, org: orgOption },
|
|
97213
97292
|
({ id, org }) => gen(function* () {
|
|
97214
97293
|
const api = yield* ApiService;
|
|
97215
|
-
yield* resolveOrgSlug(org, api);
|
|
97216
|
-
yield* api.unsetPresetAsDefault(id).pipe(
|
|
97294
|
+
const orgSlug = yield* resolveOrgSlug(org, api);
|
|
97295
|
+
yield* api.unsetPresetAsDefault(id, orgSlug).pipe(
|
|
97217
97296
|
catchTag(
|
|
97218
97297
|
"NotLoggedInError",
|
|
97219
97298
|
(e) => gen(function* () {
|
|
@@ -97242,7 +97321,7 @@ const updateCommand$1 = make$4(
|
|
|
97242
97321
|
{ id: idArg, jsonFile: jsonFileArg$2, org: orgOption },
|
|
97243
97322
|
({ id, jsonFile, org }) => gen(function* () {
|
|
97244
97323
|
const api = yield* ApiService;
|
|
97245
|
-
yield* resolveOrgSlug(org, api);
|
|
97324
|
+
const orgSlug = yield* resolveOrgSlug(org, api);
|
|
97246
97325
|
const body = yield* try_({
|
|
97247
97326
|
try: () => {
|
|
97248
97327
|
const content = fs__namespace.readFileSync(jsonFile, "utf-8");
|
|
@@ -97257,7 +97336,7 @@ const updateCommand$1 = make$4(
|
|
|
97257
97336
|
})
|
|
97258
97337
|
)
|
|
97259
97338
|
);
|
|
97260
|
-
yield* api.updatePreset(id, body).pipe(
|
|
97339
|
+
yield* api.updatePreset(id, body, orgSlug).pipe(
|
|
97261
97340
|
catchTag(
|
|
97262
97341
|
"NotLoggedInError",
|
|
97263
97342
|
(e) => gen(function* () {
|
|
@@ -40,8 +40,8 @@
|
|
|
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
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
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`, `
|
|
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` |
|
|
43
|
+
| ORG-02 | org | `aipctl org capabilities`, `aipctl org settings`, `aipctl org exit` | `getOrgCapabilities`, `getUserSettings`, `exitOrg` | api | `GET`, `GET`, `DELETE` | organization v1 `/api/cli/v1/organizations/{organizationSlug}/capabilities`; user-global v1 `/api/cli/v1/me/settings`; exit v1 `/api/cli/v1/organizations/{organizationSlug}/membership` | none | local `OrgCapabilities`, `UserSettings`, `void` | `resource/oas/modules/backend/cli/openapi.yaml` | `CliOrganizationApi`/`CliV1Api`; exit `deleteCliOrganizationMembership` | `generated-ready` | N/A | `migrate` | none; exit delegates existing member authorization, owner protection and audit | `AI-6344`; common error/deadline gate `AI-6378` | `src/core/api.test.ts`, `src/core/remaining-direct-contract.test.ts`, org tests, Backend controller test; actual CLI member exit/owner rejection |
|
|
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` | prefix `/api/cli/v1/organizations/{organizationSlug}`; `/members`; `/members/invitations`; `/members`; `/members/role` | `{ emails, role }` or `{ members, role? }`; 1..100 unique targets, email/userId/status checked against current membership | local `ListMembersResponse`, `InviteOrgMembersResponse`, `void` | `resource/oas/modules/backend/cli/openapi.yaml` | `backend/api/.../cli/generated/api/CliOrganizationApi.kt` | `generated-ready` | `P0` | `migrate` | none; preserves existing admin authorization, audit, pending/active/inactive semantics, skipped owner/self removal and invite partial failure; stale/missing target returns 409 before mutation | `AI-6344`; operational gates remain separate | API/command and Backend controller tests; actual CLI invite with LocalStack SES, role/remove for three statuses, non-admin 403, stale 409, owner protection, persisted audit |
|
|
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/cli/v1/organizations/{organizationSlug}/skills`; `/api/cli/v1/organizations/{organizationSlug}/skills/{skillId}` | query `{ count,cursor,search }`; detail query `{ maxFiles }` | local `ListSkillsResponse`, `SkillDetail`, `void` | `resource/oas/modules/backend/cli/openapi.yaml` → `v1_skills*.yaml` (DTO aliases to organization Skills OAS) | `backend/api/.../cli/generated/api/CliSkillApi.kt`; domain DTOs remain `com.querypie.duplo.api.skills.generated.model.*` | `generated-ready` | `P0` | `migrate` | none; `CliSkillApiController` delegates to the existing member authorization/audit controller | `AI-6344` | `src/core/api.test.ts`, `CliSkillDriveApiControllerTest`, Gateway registry/contract parity; production CLI and local 403/404 checks (401/429 remain common gates) |
|
|
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 |
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
| 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 |
|
|
65
65
|
| USAGE-01 | usage | `aipctl admin usage credit`, `top-users`, `daily-graph`, `daily-users`, `mcp-top` | `getCreditStatistics`, `getCreditTopUsers`, `getCreditDailyGraph`, `getCreditDailyUsers`, `getMcpTopTools` | api | `GET` | `/api/cli/v1/organizations/{organizationSlug}/admin/usage/credit`; `/admin/usage/top-users`; `/admin/usage/daily-graph`; `/admin/usage/daily-users`; `/admin/usage/mcp-top` | query `{ startDt,endDt,limit,pageNumber,pageSize,userId }`; daily-users uses one-based page/pageSize 1..100 | existing usage DTOs; `DailyUsageDetailsResponse.pagination { page,pageSize,total }` normalized to CLI output | `resource/oas/modules/backend/cli/openapi.yaml` → `paths/v1_admin_usage_*.yaml`; response aliases reuse `resource/oas/modules/backend/usage/components/schemas/*` | `backend/api/.../cli/generated/api/CliUsageApi.kt`; domain DTOs remain `com.querypie.duplo.api.usage.generated.model.*` | `generated-ready` | `P0` | `migrate` | none; dedicated adapter preserves organization admin authorization, three-month/future-date validation, and existing aggregation service | `AI-6344`; query/page workload bounds remain `AI-6413` | `src/core/usage-audit-contract.test.ts`, usage command tests, `CliUsageAuditApiControllerTest`, Gateway registry/contract parity; real production CLI verifies all five paths, 401/403/404/400 and future-date clamp |
|
|
66
66
|
| AUDIT-01 | audit | `aipctl admin audit list`, `types` | `listAuditLogs`, `listAuditEventTypes` | api | `GET` | `/api/cli/v1/organizations/{organizationSlug}/admin/audit`; `/api/cli/v1/organizations/{organizationSlug}/admin/audit/types` | query `{ eventType,page,pageSize }`; page is one-based and pageSize is 1..100 | existing `ListAuditResponse`/`AuditEventType[]`; page/total is normalized for CLI pagination output | `resource/oas/modules/backend/cli/openapi.yaml` → `paths/v1_admin_audit*.yaml`; response aliases reuse `resource/oas/modules/backend/audit/components/schemas/*` | `backend/api/.../cli/generated/api/CliAuditApi.kt`; domain DTOs remain `com.querypie.duplo.api.generated.models.*` | `generated-ready` | `P0` | `migrate` | none; dedicated adapter preserves AUDIT_LOGS capability, plan/retention/viewable-period and organization filters | `AI-6344`; audit volume/query workload bounds remain `AI-6413` | `src/core/usage-audit-contract.test.ts`, `commands/admin/audit/*.test.ts`, `CliUsageAuditApiControllerTest`, Gateway registry/contract parity; real production CLI verifies page 2/3, types, 401/403/404/400 |
|
|
67
|
-
| TUNNEL-01 | tunnel | `aipctl admin tunnel status
|
|
68
|
-
| P1-PRESET-01 | preset | `aipctl admin preset list`, `get`, `create`, `update`, `rename`, `delete`, `set-default`, `unset-default`; key rotation commands remain
|
|
67
|
+
| TUNNEL-01 | tunnel | `aipctl admin tunnel status`; `config`/`token` remain gated | `getTunnelStatus`; candidate `getTunnelConfig`, `createTunnelToken` | api | `GET`; candidate `GET`/`POST` | status `/api/cli/v1/organizations/{organizationSlug}/admin/tunnel/status`; candidates retain Web `/config`/`/token` | none | status `{ connected: boolean }` only | status `resource/oas/modules/backend/cli/openapi.yaml`; candidates Tunnel OAS | `backend/api/.../cli/generated/api/CliTunnelApi.kt#getCliTunnelStatus` | `generated-ready` | N/A | `migrate` | none for status; existing personal Tunnel service checks current user/org; token/config secret gates remain | `AI-6344`; sensitive gate `AI-6380` | status contract/adapter/registry tests; actual CLI + Go Tunnel server disconnected/Redis session connected/user isolation, token count unchanged; actual edge handshake not verified |
|
|
68
|
+
| P1-PRESET-01 | preset | `aipctl admin preset list`, `get`, `create`, `update`, `rename`, `delete`, `set-default`, `unset-default`; key rotation commands remain gated | `listPresets`, `getPreset`, `createPreset`, `updatePreset`, `renamePreset`, `deletePreset`, `setPresetAsDefault`, `unsetPresetAsDefault` | api | list/get `GET`; create `POST`; update/default set `PUT`; rename `PATCH`; delete/default unset `DELETE` | `/api/cli/v1/organizations/{organizationSlug}/admin/presets`; `/{presetId}`; `/{presetId}/default` | bounded one-based page/pageSize 1..100; default pageSize 100; existing basic mutation bodies, explicit org in path | dedicated safe `CliPreset` metadata; no installation/json commands, auth, keys or MCP URL; list CLI JSON remains a page array; delete `void` | `resource/oas/modules/backend/cli/openapi.yaml` | `backend/api/.../cli/generated/api/CliPresetApi.kt`; `CliPreset` DTOs | `generated-ready` | `P1` | `migrate` | none for basic operations; user-owned resources require member+owner+org checks despite admin namespace; read service does not mint keys/enrich remotely; domain mutation/audit reused | `AI-6344`; key gate `AI-6380`; larger workload gate `AI-6413` | `src/core/remaining-direct-contract.test.ts`, Backend safe-read/controller tests, registry/manifest/help, trailing argv tests; actual production CLI eight-operation lifecycle, ownership/accessible integration/pagination/quota/key-count/DB/audit checks |
|
|
69
69
|
|
|
70
70
|
## 공통 CLI request quota 오류 계약
|
|
71
71
|
|
|
@@ -86,7 +86,7 @@ CLI `ApiError`는 위 여섯 code에서 allowlist된 quota detail만 보존하
|
|
|
86
86
|
|
|
87
87
|
### P0 queue
|
|
88
88
|
|
|
89
|
-
- `P0-ORG-01`
|
|
89
|
+
- `P0-ORG-01` member list and invite/remove/role mutations use dedicated CLI v1 contracts (`AI-6344`); `ORG-02` exit uses DELETE membership
|
|
90
90
|
- `P0-ORG-02` org invite-link trio hidden from public beta (done in `AIP-PUB-04`)
|
|
91
91
|
- `P0-AGENT-01` / `P0-AGENT-02` moved to dedicated CLI lifecycle endpoints with metadata quota and capability checks (`AI-6344`)
|
|
92
92
|
- `P0-AGENT-03` export remains a gated transfer candidate (`AI-6380`)
|
|
@@ -98,7 +98,7 @@ CLI `ApiError`는 위 여섯 code에서 allowlist된 quota detail만 보존하
|
|
|
98
98
|
|
|
99
99
|
- `P1-INT-01` integration legacy-exception documented; current/legacy path+DTO tests added
|
|
100
100
|
- `P1-AUTO-01` Automation management uses eight dedicated v1 operations; Schedule/Webhook/My Drive lifecycle and stored safe reads are implemented. External provider metadata/mutations and `P1-AUTO-02` remain gated.
|
|
101
|
-
- `P1-PRESET-01`
|
|
101
|
+
- `P1-PRESET-01` eight basic operations use dedicated CLI v1 contracts and safe metadata DTOs (`AI-6344`); key rotation stays gated
|
|
102
102
|
- `P1-SKILL-01` skill JSON/help/docs field sync done
|
|
103
103
|
- `P1-CHAT-01` chat SSE fixture tests added for final/fallback/error cases
|
|
104
104
|
- `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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aipctl",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.3",
|
|
4
4
|
"description": "QueryPie AIP and MCP CLI tool",
|
|
5
5
|
"author": "QueryPie",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"node": ">=24.18.0"
|
|
23
23
|
},
|
|
24
24
|
"metadata": {
|
|
25
|
-
"contentHash": "
|
|
26
|
-
"wrapperHash": "
|
|
25
|
+
"contentHash": "cd3e1d96a6c80cca1c9594573468ecac8876ea644f388d0d53950cc063451a72",
|
|
26
|
+
"wrapperHash": "1f9932e5f826496deb9203873e0e543319d84afda6610a78305ffa034fd665c0",
|
|
27
27
|
"nativeHash": "006b08c3e391f4571d9b7c0f12d684fe2448106259e7e0581b10f9be362452e9"
|
|
28
28
|
},
|
|
29
29
|
"optionalDependencies": {
|